home *** CD-ROM | disk | FTP | other *** search
/ Sprite 1984 - 1993 / Sprite 1984 - 1993.iso / src / lib / c / etc / RCS / ttyDriver.c,v < prev    next >
Text File  |  1992-03-18  |  107KB  |  4,237 lines

  1. head     1.20;
  2. branch   ;
  3. access   ;
  4. symbols  sprited:1.20.1;
  5. locks    ; strict;
  6. comment  @ * @;
  7.  
  8.  
  9. 1.20
  10. date     92.03.18.16.33.08;  author rab;  state Exp;
  11. branches 1.20.1.1;
  12. next     1.19;
  13.  
  14. 1.19
  15. date     90.09.11.14.17.06;  author kupfer;  state Exp;
  16. branches ;
  17. next     1.18;
  18.  
  19. 1.18
  20. date     90.09.05.18.56.18;  author rab;  state Exp;
  21. branches ;
  22. next     1.17;
  23.  
  24. 1.17
  25. date     90.06.27.11.16.52;  author shirriff;  state Exp;
  26. branches ;
  27. next     1.16;
  28.  
  29. 1.16
  30. date     90.02.28.11.10.06;  author brent;  state Exp;
  31. branches ;
  32. next     1.15;
  33.  
  34. 1.15
  35. date     90.02.08.13.42.09;  author ouster;  state Exp;
  36. branches ;
  37. next     1.14;
  38.  
  39. 1.14
  40. date     89.07.28.16.04.40;  author ouster;  state Exp;
  41. branches ;
  42. next     1.13;
  43.  
  44. 1.13
  45. date     89.07.19.08.58.37;  author ouster;  state Exp;
  46. branches ;
  47. next     1.12;
  48.  
  49. 1.12
  50. date     89.06.03.16.46.20;  author ouster;  state Exp;
  51. branches ;
  52. next     1.11;
  53.  
  54. 1.11
  55. date     89.04.20.10.24.35;  author ouster;  state Exp;
  56. branches ;
  57. next     1.10;
  58.  
  59. 1.10
  60. date     89.04.19.15.26.54;  author ouster;  state Exp;
  61. branches ;
  62. next     1.9;
  63.  
  64. 1.9
  65. date     89.03.11.12.32.01;  author ouster;  state Exp;
  66. branches ;
  67. next     1.8;
  68.  
  69. 1.8
  70. date     89.01.19.12.36.13;  author ouster;  state Exp;
  71. branches ;
  72. next     1.7;
  73.  
  74. 1.7
  75. date     89.01.16.10.39.54;  author ouster;  state Exp;
  76. branches ;
  77. next     1.6;
  78.  
  79. 1.6
  80. date     88.10.14.13.09.19;  author brent;  state Exp;
  81. branches ;
  82. next     1.5;
  83.  
  84. 1.5
  85. date     88.10.07.19.00.59;  author douglis;  state Exp;
  86. branches ;
  87. next     1.4;
  88.  
  89. 1.4
  90. date     88.09.28.10.06.32;  author brent;  state Exp;
  91. branches ;
  92. next     1.3;
  93.  
  94. 1.3
  95. date     88.07.28.17.47.40;  author ouster;  state Exp;
  96. branches ;
  97. next     1.2;
  98.  
  99. 1.2
  100. date     88.07.25.13.27.45;  author ouster;  state Exp;
  101. branches ;
  102. next     1.1;
  103.  
  104. 1.1
  105. date     88.07.01.09.40.52;  author ouster;  state Exp;
  106. branches ;
  107. next     ;
  108.  
  109. 1.20.1.1
  110. date     92.03.18.16.34.23;  author kupfer;  state Exp;
  111. branches ;
  112. next     ;
  113.  
  114.  
  115. desc
  116. @@
  117.  
  118.  
  119. 1.20
  120. log
  121. @Lint.  (Mike checking in for Bob.)
  122. @
  123. text
  124. @/* 
  125.  * ttyDriver.c --
  126.  *
  127.  *    The routines in this module implement an emulator for the
  128.  *    UNIX 4.2 BSD tty driver.  The emulation is done in a way
  129.  *    that is independent of the specific environme (kernel, user,
  130.  *    etc.) by using a set of callback procedures to interface to
  131.  *    a raw device on one side and a client on the "cooked" side..
  132.  *
  133.  * Copyright 1987, 1989 Regents of the University of California
  134.  * Permission to use, copy, modify, and distribute this
  135.  * software and its documentation for any purpose and without
  136.  * fee is hereby granted, provided that the above copyright
  137.  * notice appear in all copies.  The University of California
  138.  * makes no representations about the suitability of this
  139.  * software for any purpose.  It is provided "as is" without
  140.  * express or implied warranty.
  141.  */
  142.  
  143. #ifndef lint
  144. static char rcsid[] = "$Header: /sprite/src/lib/c/etc/RCS/ttyDriver.c,v 1.19 90/09/11 14:17:06 kupfer Exp Locker: rab $ SPRITE (Berkeley)";
  145. #endif not lint
  146.  
  147. #include <sprite.h>
  148. #include <dev/tty.h>
  149. #include <fs.h>
  150. #include <stdio.h>
  151. #include <ctype.h>
  152. #include <errno.h>
  153. #include <signal.h>
  154. #include <stdlib.h>
  155. #include <sys/ioctl.h>
  156. #include <fmt.h>
  157. #include "td.h"
  158.  
  159. /*
  160.  * The structure below corresponds to one terminal (one call to Td_Create).
  161.  */
  162.  
  163. typedef struct Terminal {
  164.     /*
  165.      * Controlling parameters for terminal.  These all have exactly the
  166.      * same meanings as in 4.3 BSD;  see the 4.3 BSD terminal driver
  167.      * documentation for details.
  168.      */
  169.  
  170.     struct sgttyb sgttyb;
  171.     struct tchars tchars;
  172.     struct ltchars ltchars;
  173.     int localMode;
  174.     struct winsize winsize;
  175.  
  176.     /*
  177.      * State of the terminal.
  178.      */
  179.  
  180.     int column;            /* Column where the next character will be
  181.                  * echoed (i.e., cursor position).  Needed
  182.                  * in order to handle tabs correctly. */
  183.     int owner;            /* Identifier of controlling process or process
  184.                  * group (signals are sent here). */
  185.     int numOpens;        /* Number of opens that have been completed
  186.                  * successfully but not yet closed. */
  187.     int flags;            /* See below for definitions. */
  188.  
  189.     /*
  190.      * Input buffer, indexed circularly.  The buffer is reallocated
  191.      * with a larger size if it ever fills up.
  192.      */
  193.  
  194.     char *inputBuffer;        /* Input buffer area (malloc'ed). */
  195.     int inBufSize;        /* Number of bytes in inputBuffer. */
  196.     int lastAddedIn;        /* Index of last character added to buffer. */
  197.     int lastRemovedIn;        /* Index of last place from which character
  198.                  * was removed from buffer.  If lastAddedIn =
  199.                  * lastRemovedIn, the buffer is empty. */
  200.     int lastBreak;        /* Index of last break character (newline,
  201.                  * etc.) or lastRemovedIn if none in buffer. */
  202.     int lastHidden;        /* Value of lastAddedIn at the time the last
  203.                  * output to the terminal was done.  Characters
  204.                  * before this can't be smoothly backspaced
  205.                  * over, because there's output in front of
  206.                  * them on the screen.  -1 means there are no
  207.                  * editable characters in the buffer that are
  208.                  * hidden. */
  209.  
  210.     /*
  211.      * In order to backspace correctly over weird things like tabs, the
  212.      * following two variables keep track of an index position in the input
  213.      * buffer, and the column just to the right of where that character was
  214.      * echoed on the display.  KeyIndex is either the same as lastBreak or
  215.      * lastHidden or lastRemovedIn, and has two properties:  a) it will
  216.      * never be backspaced over in CRT mode;  and b) no characters beyond
  217.      * this one will be returned to the application until keyIndex is first
  218.      * advanced.
  219.      */
  220.  
  221.     int keyIndex;
  222.     int keyColumn;        /* Column just after keyIndex character. */
  223.  
  224.     /*
  225.      * Output buffer, indexed circularly.  This buffer also grows
  226.      * dynamically if necessary (this is necessary so that new room can
  227.      * be made for characters being echoed, even if the buffer was
  228.      * previously "full").  However, the cooked side of the terminal
  229.      * is marked "not ready for output" whenever there are more than
  230.      * cookedOutputLimit characters in the buffer (but any call to
  231.      * Td_PutCooked will always complete;  it is up to the cooked-side
  232.      * callbacks to stop calling Td_PutCooked).  The goal here is to
  233.      * keep the application from getting too many characters ahead of
  234.      * the actual device.
  235.      */
  236.  
  237.     char *outputBuffer;        /* Output buffer area (malloc'ed). */
  238.     int outBufSize;        /* Number of bytes in outputBuffer. */
  239.     int lastAddedOut;        /* Index of last character added to
  240.                  * outputBuffer. */
  241.     int lastRemovedOut;        /* Index of last character removed from
  242.                  * outputBufer. */
  243.     int outCharsBuffered;    /* Number of characters bufferred in
  244.                  * outputBuffer. */
  245.     int cookedOutputLimit;    /* Mark cooked side not ready for output
  246.                  * whenever outCharsBuffered is greater
  247.                  * than this. */
  248.  
  249.     /*
  250.      * Callback procedures and data provided by the client:
  251.      */
  252.  
  253.     int (*cookedProc)_ARGS_((ClientData, int operation, int inBufSize, 
  254.                  char *inBuffer, int outBufSize,
  255.                  char *outBuffer)); 
  256.                 /* Procedure to call to register change
  257.                  * in state of cooked-side interface. */
  258.     ClientData cookedData;    /* Value to pass to cookedProc. */
  259.     int (*rawProc)_ARGS_((ClientData, int operation, int inBufSize,
  260.               char *inBuffer, int outBufSize,
  261.               char *outBuffer));
  262.                 /* Procedure to call to register change
  263.                  * in state of raw-side interface. */
  264.     ClientData rawData;        /* Value to pass to rawProc. */
  265. } Terminal;
  266.  
  267. /* Flag values:
  268.  *
  269.  * EXCLUSIVE:        No more opens should be allowed until terminal
  270.  *            has been completely closed.
  271.  * BS_IN_PROGRESS:    A printing backspace sequence (delimited by
  272.  *            "\" and "/") is in progress, and will eventually
  273.  *            need the closing "/".
  274.  * LITERAL_NEXT:    The next character should be taken literally,
  275.  *            and should be put into the input buffer with
  276.  *            no special interpretation.
  277.  * OWNER_FAMILY:    1 means the owner is a process family.  0 means
  278.  *            it's a single process.
  279.  * OUTPUT_OFF:        1 means output to the raw device has been stopped,
  280.  *            for example because ^S was typed.
  281.  */
  282.  
  283. #define EXCLUSIVE        0x1
  284. #define BS_IN_PROGRESS        0x2
  285. #define LITERAL_NEXT        0x4
  286. #define OWNER_FAMILY        0x8
  287. #define OUTPUT_OFF        0x10
  288.  
  289. /*
  290.  * Default values for tty parameters:
  291.  */
  292.  
  293. struct sgttyb sgttybDefault = {
  294.     B9600, B9600, 010, 025, EVENP|ODDP|CRMOD|ECHO
  295. };
  296. struct tchars tcharsDefault = {
  297.     03, 034, 021, 023, 04, -1
  298. };
  299. struct ltchars ltcharsDefault = {
  300.     032, 031, 022, 017, 027, 026
  301. };
  302. int localModeDefault = LCRTBS|LCRTERA|LCRTKIL|LCTLECH;
  303. struct winsize winsizeDefault = {
  304.     0, 0, 0, 0
  305. };
  306.  
  307. /*
  308.  * Macros for moving buffer pointers forward and backward circularly.
  309.  */
  310.  
  311. #define NEXT(src, size, dst)         \
  312.     (dst) = (src)+1;            \
  313.     if ((dst) >= (size)) {        \
  314.     (dst) = 0;            \
  315.     }
  316.  
  317. #define PREV(src, size, dst)        \
  318.     (dst) = (src)-1;            \
  319.     if ((dst) < 0) {            \
  320.     (dst) = (size)-1;            \
  321.     }
  322.  
  323. int td_Debug = 0;
  324.  
  325. /*
  326.  * Forward declarations for procedures defined later in this file:
  327.  */
  328.  
  329. static void    TdBackspace _ARGS_((Terminal *tPtr));
  330. static void    TdEcho _ARGS_((Terminal *tPtr, int c));
  331. static void    TdFlushInput _ARGS_((Terminal *tPtr));
  332. static void    TdFlushOutput _ARGS_((Terminal *tPtr));
  333. static void    TdPutChar _ARGS_((Terminal *tPtr, int c));
  334. static void    TdRetypeInput _ARGS_((Terminal *tPtr, int start));
  335. static int    FormatInput _ARGS_((int command, Fmt_Format format,
  336.                     int inputSize, Address input,
  337.                     int *newInputSizePtr, Address newInput));
  338. static int    FormatOutput _ARGS_((int command, Fmt_Format format,
  339.                      int outputSize, Address output,
  340.                      int *newOutputSizePtr,
  341.                      Address newOutput));
  342.  
  343.  
  344. /*
  345.  *----------------------------------------------------------------------
  346.  *
  347.  * Td_Create --
  348.  *
  349.  *    This procedure creates and initializes a new terminal
  350.  *    driver.
  351.  *
  352.  * Results:
  353.  *    The return value is a handle that is used to refer to the
  354.  *    driver when calling other Td_ procedures, such as Td_Delete.
  355.  *
  356.  * Side effects:
  357.  *    The procedures cookedProc and rawProc may be invoked by
  358.  *    other procedures in this module at later times.  See the
  359.  *    man page for details.
  360.  *
  361.  *----------------------------------------------------------------------
  362.  */
  363.  
  364. Td_Terminal
  365. Td_Create(bufferSize, cookedProc, cookedData, rawProc, rawData)
  366.     int bufferSize;        /* How much buffer space to allow on
  367.                  * output. */
  368.     int (*cookedProc)_ARGS_((ClientData, int operation, int inBufSize, 
  369.                  char *inBuffer, int outBufSize,
  370.                  char *outBuffer)); 
  371.                 /* Procedure to call for control operations
  372.                  * on cooked side of driver. */
  373.     ClientData cookedData;    /* Arbitrary value, provided by caller,
  374.                  * which will be passed to cookedProc
  375.                  * whenever it is invoked. */
  376.     int (*rawProc)_ARGS_((ClientData, int operation, int inBufSize,
  377.               char *inBuffer, int outBufSize,
  378.               char *outBuffer));
  379.                 /* Procedure to call for control operations
  380.                  * on raw side of driver. */
  381.     ClientData rawData;        /* Arbitrary value, provided by caller,
  382.                  * which will be passed to rawProc whenever
  383.                  * it is invoked. */
  384. {
  385.     register Terminal *tPtr;
  386.     Td_BaudRate baud;
  387.  
  388.     tPtr = (Terminal *) malloc(sizeof(Terminal));
  389.     tPtr->sgttyb = sgttybDefault;
  390.     tPtr->tchars = tcharsDefault;
  391.     tPtr->ltchars = ltcharsDefault;
  392.     tPtr->localMode = localModeDefault;
  393.     tPtr->winsize = winsizeDefault;
  394.     tPtr->column = 0;
  395.     tPtr->owner = -1;
  396.     tPtr->flags = 0;
  397.     tPtr->inputBuffer = (char *) malloc(100);
  398.     tPtr->inBufSize = 100;
  399.     tPtr->lastAddedIn = 0;
  400.     tPtr->lastRemovedIn = 0;
  401.     tPtr->lastBreak = 0;
  402.     tPtr->lastHidden = -1;
  403.     tPtr->keyIndex = 0;
  404.     tPtr->keyColumn = 0;
  405.     tPtr->outputBuffer = (char *) malloc(1000);
  406.     tPtr->outBufSize = 1000;
  407.     tPtr->lastAddedOut = 0;
  408.     tPtr->lastRemovedOut = 0;
  409.     tPtr->outCharsBuffered = 0;
  410.     tPtr->cookedOutputLimit = bufferSize;
  411.     tPtr->cookedProc = cookedProc;
  412.     tPtr->cookedData = cookedData;
  413.     tPtr->rawProc = rawProc;
  414.     tPtr->rawData = rawData;
  415.  
  416.     /*
  417.      * Fetch the actual baud rate from the raw device manager.
  418.      */
  419.  
  420.     if ((*rawProc)(rawData, TD_RAW_GET_BAUD_RATE, 0, (char *) NULL,
  421.         sizeof(baud), (char *) &baud) == sizeof(baud)) {
  422.     tPtr->sgttyb.sg_ispeed = baud.ispeed;
  423.     tPtr->sgttyb.sg_ospeed = baud.ospeed;
  424.     }
  425.  
  426.     return (Td_Terminal) tPtr;
  427. }
  428.  
  429. /*
  430.  *----------------------------------------------------------------------
  431.  *
  432.  *  Td_Delete --
  433.  *
  434.  *    Close down a terminal driver, destroying all of the state
  435.  *    associated with it.
  436.  *
  437.  * Results:
  438.  *    None.
  439.  *
  440.  * Side effects:
  441.  *    A hangup is simulated on the cooked side of the driver, and
  442.  *    memory is released.  The caller should never again use
  443.  *    terminal.
  444.  *
  445.  *----------------------------------------------------------------------
  446.  */
  447.  
  448. void
  449. Td_Delete(terminal)
  450.     Td_Terminal terminal;    /* Token identifying terminal (returned
  451.                  * by previous call to Td_Create). */
  452. {
  453.     register Terminal *tPtr = (Terminal *) terminal;
  454.  
  455.     (*tPtr->rawProc)(tPtr->rawData, TD_RAW_SHUTDOWN, 0, (char *) NULL,
  456.         0, (char *) NULL);
  457.     free((char *) tPtr->inputBuffer);
  458.     free((char *) tPtr->outputBuffer);
  459.     free((char *) tPtr);
  460. }
  461.  
  462. /*
  463.  *----------------------------------------------------------------------
  464.  *
  465.  * Td_Open --
  466.  *
  467.  *    This procedure should be called before accepting a new
  468.  *    "open" for a terminal.  It indicates whether new opens
  469.  *    are permitted.
  470.  *
  471.  * Results:
  472.  *    The return value is zero if the open is to be permitted,
  473.  *    and a non-zero errno value if it is to be denied.  If the
  474.  *    open is successful, *selectBitsPtr is filled in with the
  475.  *    initial select state for the terminal.
  476.  *
  477.  * Side effects:
  478.  *    Information counting open streams on the terminal gets
  479.  *    updated.
  480.  *
  481.  *----------------------------------------------------------------------
  482.  */
  483.  
  484. int
  485. Td_Open(terminal, selectBitsPtr)
  486.     Td_Terminal terminal;        /* Token for the terminal to be
  487.                      * checked. */
  488.     int *selectBitsPtr;            /* Put initial select state here. */
  489. {
  490.     register Terminal *tPtr = (Terminal *) terminal;
  491.  
  492.     if (tPtr->flags & EXCLUSIVE) {
  493.     return EBUSY;
  494.     }
  495.     tPtr->numOpens++;
  496.     *selectBitsPtr = 0;
  497.     if ((tPtr->lastBreak != tPtr->lastRemovedIn)
  498.         || (tPtr->localMode & LPENDIN)) {
  499.     *selectBitsPtr |= FS_READABLE;
  500.     }
  501.     if (tPtr->outCharsBuffered < tPtr->cookedOutputLimit) {
  502.     *selectBitsPtr |= FS_WRITABLE;
  503.     }
  504.     return 0;
  505. }
  506.  
  507. /*
  508.  *----------------------------------------------------------------------
  509.  *
  510.  * Td_Close --
  511.  *
  512.  *    This procedure should be called whenever all of the I/O streams
  513.  *    associated with a single open on a terminal have been closed.
  514.  *
  515.  * Results:
  516.  *    none.
  517.  *
  518.  * Side effects:
  519.  *    State in the terminal is updated to reflect the close.
  520.  *
  521.  *----------------------------------------------------------------------
  522.  */
  523.  
  524. void
  525. Td_Close(terminal)
  526.     Td_Terminal terminal;        /* Token for the terminal to be
  527.                      * checked. */
  528. {
  529.     register Terminal *tPtr = (Terminal *) terminal;
  530.  
  531.     tPtr->numOpens--;
  532.     if (tPtr->numOpens == 0) {
  533.     tPtr->flags &= ~EXCLUSIVE;
  534.     }
  535. }
  536.  
  537. /*
  538.  *----------------------------------------------------------------------
  539.  *
  540.  * Td_GetCooked --
  541.  *
  542.  *    Retrieve characters that are ready to be read from the cooked
  543.  *    side of a terminal driver.
  544.  *
  545.  * Results:
  546.  *    The return value is normally 0.  If non-zero, it indicates
  547.  *    that an error occurred and holds a UNIX errno.  Most often,
  548.  *    this is EWOULDBLOCK, meaning that no characters were
  549.  *    available.  The value at numCharsPtr is overwritten with the
  550.  *    actual number of characters returned at buffer, and will be
  551.  *    0 if an error or end-of-file occurred.  *SigNumPtr is overwritten
  552.  *    with a signal to send to the invoking process, or 0.  *SelectBitsPtr
  553.  *    is updated to reflect the readability of the terminal.
  554.  *
  555.  * Side effects:
  556.  *    Characters are removed from the terminal's input buffer.
  557.  *
  558.  *----------------------------------------------------------------------
  559.  */
  560.  
  561. int
  562. Td_GetCooked(terminal, pID, familyID, numCharsPtr, buffer, 
  563.     sigNumPtr, selectBitsPtr)
  564.     Td_Terminal terminal;    /* Token identifying terminal. */
  565.     int pID;            /* Process invoking operation. */
  566.     int familyID;        /* Family of pID. */
  567.     int *numCharsPtr;        /* Points to maximum number of characters to
  568.                  * read from terminal. Overwritten by number
  569.                  * of chars. actually returned. */
  570.     char *buffer;        /* Where to place characters that are read. */
  571.     int *sigNumPtr;        /* Overwrite this with the number of a signal
  572.                  * to generate for the calling process.  0
  573.                  * means no signal. */
  574.     int *selectBitsPtr;        /* The FS_READABLE bit in this word gets
  575.                  * updated to reflect whether or not there
  576.                  * are still more readable characters after
  577.                  * the ones returned. */
  578. {
  579.     register Terminal *tPtr = (Terminal *) terminal;
  580.     register char *dest;
  581.     int count, result;
  582.  
  583.     *sigNumPtr = 0;
  584.  
  585.     /*
  586.      * See if this process owns the terminal.  If not, then signal it
  587.      * and don't give it any input.
  588.      */
  589.  
  590.     if (!(tPtr->flags & OWNER_FAMILY)) {
  591.     if ((pID != tPtr->owner) && (tPtr->owner != -1)) {
  592.         notOwner:
  593.         *sigNumPtr = SIGTTIN;
  594.         *numCharsPtr = 0;
  595.         result = EINTR;
  596.         goto done;
  597.     }
  598.     } else if ((familyID != tPtr->owner) && (tPtr->owner != -1)) {
  599.     goto notOwner;
  600.     }
  601.  
  602.     /*
  603.      * Re-echo buffered characters, if so requested.
  604.      */
  605.  
  606.     if (tPtr->localMode & LPENDIN) {
  607.     int oldCharsBuffered;
  608.  
  609.     oldCharsBuffered = tPtr->outCharsBuffered;
  610.     tPtr->localMode &= ~LPENDIN;
  611.     TdRetypeInput(tPtr, tPtr->lastRemovedIn);
  612.     if ((oldCharsBuffered == 0) && (tPtr->outCharsBuffered != 0) &&
  613.         !(tPtr->flags & OUTPUT_OFF)) {
  614.         (*tPtr->rawProc)(tPtr->rawData, TD_RAW_OUTPUT_READY,
  615.             0, (char *) NULL, 0, (char *) NULL);
  616.     }
  617.     }
  618.  
  619.     /*
  620.      * Make sure there's information ready for the terminal.  If not,
  621.      * then block the process.
  622.      */
  623.  
  624.     if (tPtr->lastBreak == tPtr->lastRemovedIn) {
  625.     *numCharsPtr = 0;
  626.     *selectBitsPtr &= ~FS_READABLE;
  627.     return EWOULDBLOCK;
  628.     }
  629.  
  630.     /*
  631.      * Copy bytes from the input buffer to the caller's buffer,
  632.      * and update the terminal's input buffer pointer.
  633.      */
  634.  
  635.     count = 0;
  636.     dest = buffer;
  637.     while ((tPtr->lastRemovedIn != tPtr->lastBreak) &&
  638.         (count < *numCharsPtr)) {
  639.     register char c;
  640.  
  641.     NEXT(tPtr->lastRemovedIn, tPtr->inBufSize, tPtr->lastRemovedIn);
  642.     count++;
  643.     c = tPtr->inputBuffer[tPtr->lastRemovedIn];
  644.     *dest = c;
  645.     dest++;
  646.     if (!(tPtr->sgttyb.sg_flags & (RAW|CBREAK))) {
  647.         if (c == tPtr->tchars.t_eofc) {
  648.         count--;        /* Don't return end-of-file chars. */
  649.         break;
  650.         } else if ((c == '\n') || (c == tPtr->tchars.t_brkc)) {
  651.         break;
  652.         }
  653.     }
  654.     }
  655.     *numCharsPtr = count;
  656.     result = 0;
  657.  
  658.     done:
  659.     if (tPtr->lastBreak == tPtr->lastRemovedIn) {
  660.     *selectBitsPtr &= ~FS_READABLE;
  661.     } else {
  662.     *selectBitsPtr |= FS_READABLE;
  663.     }
  664.     return result;
  665. }
  666.  
  667. /*
  668.  *----------------------------------------------------------------------
  669.  *
  670.  * Td_PutCooked --
  671.  *
  672.  *    Add characters to the output buffer for a terminal.
  673.  *
  674.  * Results:
  675.  *    The return value is always 0 (the output is grown enough to
  676.  *    hold all the output characters).  The value at *numBytesPtr
  677.  *    is left unchanged to indicate that all the characters were
  678.  *    accepted, *sigNumPtr is overwritten with a signal to send
  679.  *    to the invoking process (or 0), and *selectBitsPtr is updated
  680.  *    to reflect whether the terminal's output buffer is now full.
  681.  *
  682.  * Side effects:
  683.  *    Output processing is performed on the characters in buffer,
  684.  *    and they are queued for output on the terminal's raw side.
  685.  *
  686.  *----------------------------------------------------------------------
  687.  */
  688.  
  689.     /* ARGSUSED */
  690. int
  691. Td_PutCooked(terminal, numBytesPtr, buffer, sigNumPtr, selectBitsPtr)
  692.     Td_Terminal terminal;    /* Token identifying terminal. */
  693.     int *numBytesPtr;        /* Points to maximum number of characters
  694.                  * to write to terminal.  Not modified
  695.                  * by this procedure. */
  696.     register char *buffer;    /* Characters to write. */
  697.     int *sigNumPtr;        /* Overwrite this with the number of a signal
  698.                  * to generate for the calling process.  0
  699.                  * means no signal. */
  700.     int *selectBitsPtr;        /* The FS_WRITABLE bit in this word gets
  701.                  * updated to reflect whether or not there
  702.                  * are still more space available in the
  703.                  * terminal's output buffer. */
  704. {
  705.     register Terminal *tPtr = (Terminal *) terminal;
  706.     register char c;
  707.     int i, oldCharsBuffered;
  708.  
  709.     *sigNumPtr = 0;
  710.  
  711.     oldCharsBuffered = tPtr->outCharsBuffered;
  712.     for (i = 0; i < *numBytesPtr; i++, buffer++) {
  713.     c = *buffer;
  714.     if ((tPtr->sgttyb.sg_flags & RAW) || (tPtr->localMode & LLITOUT)) {
  715.         TdPutChar(tPtr, c);
  716.         continue;
  717.     }
  718.     c &= 0177;
  719.     if (c == 04) {    /* End of file (^D) ignored */
  720.         continue;
  721.     } else if ((c == '\n') && (tPtr->sgttyb.sg_flags & CRMOD)) {
  722.         TdPutChar(tPtr, '\r');
  723.         TdPutChar(tPtr, '\n');
  724.     } else {
  725.         TdPutChar(tPtr, c);
  726.     }
  727.     }
  728.     tPtr->keyIndex = tPtr->lastAddedIn;
  729.     tPtr->keyColumn = tPtr->column;
  730.     if (tPtr->lastAddedIn != tPtr->lastRemovedIn) {
  731.     tPtr->lastHidden = tPtr->lastAddedIn;
  732.     }
  733.     if ((oldCharsBuffered == 0) && (tPtr->outCharsBuffered != 0) &&
  734.         !(tPtr->flags & OUTPUT_OFF)) {
  735.     (*tPtr->rawProc)(tPtr->rawData, TD_RAW_OUTPUT_READY,
  736.         0, (char *) NULL, 0, (char *) NULL);
  737.     }
  738.     if (tPtr->outCharsBuffered >= tPtr->cookedOutputLimit) {
  739.     *selectBitsPtr &= ~FS_WRITABLE;
  740.     } else {
  741.     *selectBitsPtr |= FS_WRITABLE;
  742.     }
  743.     return 0;
  744. }
  745.  
  746. /*
  747.  *----------------------------------------------------------------------
  748.  *
  749.  * Td_ControlCooked --
  750.  *
  751.  *    This procedure is used to invoke iocontrol operations on the
  752.  *    cooked side of a terminal driver.
  753.  *
  754.  * Results:
  755.  *    If the operation completed successfully then the return value
  756.  *    is zero.  If the operation failed, then the return value is a
  757.  *    UNIX errno indicating what went wrong.  *SigNumPtr gets
  758.  *    overwritten with the number of a signal to send to the invoking
  759.  *    process (or 0), and *selectBitsPtr gets filled in with information
  760.  *    about whether or not the terminal is now readable or writable.
  761.  *
  762.  * Side effects:
  763.  *    Depends on the iocontrol;  see the tty(4) man page for details.
  764.  *
  765.  *----------------------------------------------------------------------
  766.  */
  767.  
  768.     /* ARGSUSED */
  769. int
  770. Td_ControlCooked(terminal, command, format, inputSize, input, outputSizePtr,
  771.     output, sigNumPtr, selectBitsPtr)
  772.     Td_Terminal terminal;        /* Token for terminal. */
  773.     int command;            /* Iocontrol operation to perform
  774.                      * (    e.g. TIOCGETP). */
  775.     Fmt_Format format;            /* Byte-order/alignment format */
  776.     int inputSize;            /* Size of input, in bytes. */
  777.     char *input;            /* Input buffer:  contains information
  778.                      * provided by client as input to
  779.                      * operation. */
  780.     int *outputSizePtr;            /* Largest amount of output that
  781.                      * client is prepared to receive.  This
  782.                      * value is overwritten with the count
  783.                      * of actual bytes returned. */
  784.     char *output;            /* Place to store output bytes;
  785.                      * provided by caller. */
  786.     int *sigNumPtr;            /* Overwrite this with the number of
  787.                      * a signal to generate for the
  788.                      * calling process.  0 means no
  789.                      * signal. */
  790.     int *selectBitsPtr;            /* Store new select state of terminal
  791.                      * here. */
  792. {
  793.     register Terminal *tPtr = (Terminal *) terminal;
  794.     int count, result;
  795.     char *out = (char *) NIL;
  796.     int i;
  797.     Ioc_Owner owner;
  798.     int oldIspeed, oldOspeed, oldFlags, oldStopc, oldStartc;
  799.  
  800.     /*
  801.      * The union below describes all of the possible formats in which
  802.      * the input area may appear.
  803.      */
  804.  
  805.     typedef union {
  806.     int        i;
  807.     char        chars[20];
  808.     struct sgttyb    sgttyb;
  809.     struct tchars    tchars;
  810.     struct ltchars    ltchars;
  811.     Ioc_Owner    owner;
  812.     struct winsize    winsize;
  813.     } InBuf;
  814.     InBuf newInputBuf;
  815.     register InBuf *in = (InBuf *) input;
  816.  
  817.     if (td_Debug) {
  818.     printf("Td_ControlCooked: command %d\n", command);
  819.     }
  820.  
  821.     if (format != FMT_MY_FORMAT) {
  822.     /*
  823.      * Fix up the formatting of the input buffer.
  824.      */
  825.     int newSize = sizeof(newInputBuf);
  826.     if (FormatInput(command, format, inputSize, input,
  827.                 &newSize, (Address) &newInputBuf) != FMT_OK) {
  828.         goto invalid;
  829.     }
  830.     in = &newInputBuf;
  831.     inputSize = newSize;
  832.     }
  833.     /*
  834.      * Save certain pieces of information about the terminal so that
  835.      * if they change we can call the raw control procedure.
  836.      */
  837.  
  838.     oldIspeed = tPtr->sgttyb.sg_ispeed;
  839.     oldOspeed = tPtr->sgttyb.sg_ospeed;
  840.     oldFlags = tPtr->sgttyb.sg_flags;
  841.     oldStopc = tPtr->tchars.t_stopc;
  842.     oldStartc = tPtr->tchars.t_startc;
  843.  
  844.     *sigNumPtr = 0;
  845.     count = 0;
  846.     switch (command) {
  847.  
  848.     case IOC_TTY_SET_DISCIPLINE:
  849.         if ((inputSize != sizeof(int))
  850.             || (in->i != NTTYDISC)) {
  851.         goto invalid;
  852.         }
  853.         break;
  854.  
  855.     case IOC_TTY_GET_DISCIPLINE:
  856.         if (inputSize != 0) {
  857.         goto invalid;
  858.         }
  859.         i = NTTYDISC;
  860.         out = (char *) &i;
  861.         count = sizeof(int);
  862.         break;
  863.  
  864.     case IOC_TTY_GETP:
  865.         if (inputSize != 0) {
  866.         goto invalid;
  867.         }
  868.         out = (char *) &tPtr->sgttyb;
  869.         count = sizeof(struct sgttyb);
  870.         break;
  871.  
  872.     case IOC_TTY_SETP:
  873.         /*
  874.          * Technically, this code should delay until all characters
  875.          * currently buffered for output have been printed, but
  876.          * there's no easy way to do that here:  ioctls must complete
  877.          * immediately.
  878.          */
  879.         TdFlushInput(tPtr);
  880.     case IOC_TTY_SETN:
  881.         if (inputSize != sizeof(struct sgttyb)) {
  882.         goto invalid;
  883.         }
  884.         if ((tPtr->sgttyb.sg_flags ^ in->sgttyb.sg_flags) & RAW) {
  885.         /*
  886.          * Going into or out of raw mode;  always flush input
  887.          * buffer.
  888.          */
  889.  
  890.         TdFlushInput(tPtr);
  891.         }
  892.         tPtr->sgttyb = in->sgttyb;
  893.         break;
  894.  
  895.     case IOC_TTY_EXCL:
  896.         if (inputSize != 0) {
  897.         goto invalid;
  898.         }
  899.         tPtr->flags |= EXCLUSIVE;
  900.         break;
  901.  
  902.     case IOC_TTY_NXCL:
  903.         if (inputSize != 0) {
  904.         goto invalid;
  905.         }
  906.         tPtr->flags &= ~EXCLUSIVE;
  907.         break;
  908.  
  909.     case IOC_TTY_HUP_ON_CLOSE:        /* Not implemented. */
  910.         goto invalid;
  911.  
  912.     case IOC_TTY_FLUSH: {
  913.         /*
  914.          * For compatibility with TIOCFLUSH, we accept one
  915.          * integer argument which has the FREAD and FWRITE bits in it.
  916.          */
  917.         int flags;
  918.         if (inputSize == 0) {
  919.         flags = 0;
  920.         } else {
  921.         flags = in->i;
  922.         }
  923. #ifndef FREAD
  924. #define FREAD    0x1
  925. #define FWRITE    0x2
  926. #endif
  927.         if (flags == 0) {
  928.         flags = FREAD|FWRITE;
  929.         }
  930.         if (flags & FREAD) {
  931.         TdFlushInput(tPtr);
  932.         }
  933.         if (flags & FWRITE) {
  934.         TdFlushOutput(tPtr);
  935.         }
  936.         break;
  937.     }
  938.     case IOC_TTY_INSERT_CHAR:
  939.         if (inputSize != 1) {
  940.         goto invalid;
  941.         }
  942.         Td_PutRaw((Td_Terminal) tPtr, 1, &in->chars[0]);
  943.         break;
  944.  
  945.     case IOC_TTY_SET_BREAK:
  946.         (*tPtr->rawProc)(tPtr->rawData, TD_RAW_START_BREAK,
  947.             0, (char *) NULL, 0, (char *) NULL);
  948.         break;
  949.  
  950.     case IOC_TTY_CLEAR_BREAK:
  951.         (*tPtr->rawProc)(tPtr->rawData, TD_RAW_START_BREAK,
  952.             0, (char *) NULL, 0, (char *) NULL);
  953.         break;
  954.  
  955.     case IOC_TTY_SET_DTR:
  956.         (*tPtr->rawProc)(tPtr->rawData, TD_RAW_SET_DTR,
  957.             0, (char *) NULL, 0, (char *) NULL);
  958.         break;
  959.  
  960.     case IOC_TTY_CLEAR_DTR:    
  961.         (*tPtr->rawProc)(tPtr->rawData, TD_RAW_CLEAR_DTR,
  962.             0, (char *) NULL, 0, (char *) NULL);
  963.         break;
  964.  
  965.     case IOC_GET_OWNER:
  966.         if (inputSize != 0) {
  967.         goto invalid;
  968.         }
  969.         owner.id = tPtr->owner;
  970.         if (tPtr->flags & OWNER_FAMILY) {
  971.         owner.procOrFamily = IOC_OWNER_FAMILY;
  972.         } else {
  973.         owner.procOrFamily = IOC_OWNER_PROC;
  974.         }
  975.         out = (char *) &owner;
  976.         count = sizeof(owner);
  977.         break;
  978.  
  979.     case IOC_SET_OWNER:
  980.         if (inputSize != sizeof(Ioc_Owner)) {
  981.         goto invalid;
  982.         }
  983.         tPtr->owner = in->owner.id;
  984.         if (in->owner.procOrFamily == IOC_OWNER_FAMILY) {
  985.         tPtr->flags |= OWNER_FAMILY;
  986.         } else {
  987.         tPtr->flags &= ~OWNER_FAMILY;
  988.         }
  989.         break;
  990.  
  991.     case IOC_NUM_READABLE:
  992.         i = tPtr->lastBreak - tPtr->lastRemovedIn;
  993.         if (i < 0) {
  994.         i += tPtr->inBufSize;
  995.         }
  996.         out = (char *) &i;
  997.         count = sizeof(int);
  998.         break;
  999.  
  1000.     case IOC_TTY_GET_TCHARS:
  1001.         if (inputSize != 0) {
  1002.         goto invalid;
  1003.         }
  1004.         out = (char *) &tPtr->tchars;
  1005.         count = sizeof(struct tchars);
  1006.         break;
  1007.  
  1008.     case IOC_TTY_SET_TCHARS:
  1009.         if (inputSize != sizeof(struct tchars)) {
  1010.         goto invalid;
  1011.         }
  1012.         tPtr->tchars = in->tchars;
  1013.         break;
  1014.  
  1015.     case IOC_TTY_BIS_LM:
  1016.         if (inputSize != sizeof(int)) {
  1017.         goto invalid;
  1018.         }
  1019.         tPtr->localMode |= in->i;
  1020.         break;
  1021.  
  1022.     case IOC_TTY_BIC_LM:
  1023.         if (inputSize != sizeof(int)) {
  1024.         goto invalid;
  1025.         }
  1026.         tPtr->localMode &= ~in->i;
  1027.         break;
  1028.  
  1029.     case IOC_TTY_SET_LM:
  1030.         if (inputSize != sizeof(int)) {
  1031.         goto invalid;
  1032.         }
  1033.         tPtr->localMode = in->i;
  1034.         break;
  1035.  
  1036.     case IOC_TTY_GET_LM:
  1037.         if (inputSize != 0) {
  1038.         goto invalid;
  1039.         }
  1040.         out = (char *) &tPtr->localMode;
  1041.         count = sizeof(int);
  1042.         break;
  1043.  
  1044.     case IOC_TTY_SET_LTCHARS:
  1045.         if (inputSize != sizeof(struct ltchars)) {
  1046.         goto invalid;
  1047.         }
  1048.         tPtr->ltchars = in->ltchars;
  1049.         break;
  1050.  
  1051.     case IOC_TTY_GET_LTCHARS:
  1052.         if (inputSize != 0) {
  1053.         goto invalid;
  1054.         }
  1055.         out = (char *) &tPtr->ltchars;
  1056.         count = sizeof(struct ltchars);
  1057.         break;
  1058.  
  1059.     case IOC_GET_FLAGS:
  1060.         i = 0;
  1061.         out = (char *) &i;
  1062.         count = sizeof(int);
  1063.         break;
  1064.     case IOC_SET_FLAGS:
  1065.     case IOC_SET_BITS:
  1066.     case IOC_CLEAR_BITS:
  1067.     case IOC_TTY_NOT_CONTROL_TTY:
  1068.         break;
  1069.  
  1070.     case IOC_TTY_GET_WINDOW_SIZE:
  1071.         if (inputSize != 0) {
  1072.         goto invalid;
  1073.         }
  1074.         out = (char *) &tPtr->winsize;
  1075.         count = sizeof(struct winsize);
  1076.         break;
  1077.  
  1078.     case IOC_TTY_SET_WINDOW_SIZE: {
  1079.         Td_Signal signalInfo;
  1080.         if (inputSize != sizeof(struct winsize)) {
  1081.         goto invalid;
  1082.         }
  1083.         tPtr->winsize = in->winsize;
  1084.         signalInfo.sigNum = SIGWINCH;
  1085.         signalInfo.groupID = tPtr->owner;
  1086.         (*tPtr->cookedProc)(tPtr->cookedData, TD_COOKED_SIGNAL,
  1087.             sizeof(signalInfo), (char *) &signalInfo,
  1088.             0, (char *) NULL);
  1089.         break;
  1090.     }
  1091.  
  1092.     default:
  1093.         goto invalid;
  1094.     }
  1095.     /*
  1096.      * Fix up output buffer for the client.  At this point
  1097.      * count = size of output data
  1098.      * out = pointer to output data
  1099.      * Here we rely on the Fmt_ library doing essentially a bcopy
  1100.      * if our format and the client's format are the same.
  1101.      */
  1102.     if (count != 0) {
  1103.     result = FormatOutput(command, format, count, out,
  1104.                   outputSizePtr, output);
  1105.     if (result != FMT_OK) {
  1106.         result = EINVAL;
  1107.         if (td_Debug) {
  1108.         printf("Td_ControlCooked: command %d invalid output\n", command);
  1109.         }
  1110.     }
  1111.     } else {
  1112.     *outputSizePtr = 0;
  1113.     result = 0;
  1114.     }
  1115.  
  1116.     /*
  1117.      * Call the raw control procedure if anything changed that it needs
  1118.      * to know about.
  1119.      */
  1120.  
  1121.     if ((oldIspeed != tPtr->sgttyb.sg_ispeed)
  1122.         || (oldOspeed != tPtr->sgttyb.sg_ospeed)) {
  1123.     Td_BaudRate baud, baud2;
  1124.  
  1125.     baud.ispeed = tPtr->sgttyb.sg_ispeed;
  1126.     baud.ospeed = tPtr->sgttyb.sg_ospeed;
  1127.     if ((*tPtr->rawProc)(tPtr->rawData, TD_RAW_SET_BAUD_RATE,
  1128.         sizeof(baud), (char *) &baud,
  1129.         sizeof(baud2), (char *) &baud2) == sizeof(baud2)) {
  1130.  
  1131.         /*
  1132.          * Device has overridden the baud-rate change;  take its advice.
  1133.          */
  1134.  
  1135.         tPtr->sgttyb.sg_ispeed = baud2.ispeed;
  1136.         tPtr->sgttyb.sg_ospeed = baud2.ospeed;
  1137.     }
  1138.     }
  1139.     if (((oldFlags & RAW) != (tPtr->sgttyb.sg_flags & RAW))
  1140.         || (oldStopc != tPtr->tchars.t_stopc)
  1141.         || (oldStartc != tPtr->tchars.t_startc)) {
  1142.     Td_FlowChars flow;
  1143.  
  1144.     if (tPtr->sgttyb.sg_flags & RAW) {
  1145.         flow.stop = flow.start = -1;
  1146.     } else {
  1147.         flow.stop = tPtr->tchars.t_stopc;
  1148.         flow.start = tPtr->tchars.t_startc;
  1149.     }
  1150.     (*tPtr->rawProc)(tPtr->rawData, TD_RAW_FLOW_CHARS,
  1151.         sizeof(flow), (char *) &flow, 0, (char *) NULL);
  1152.     }
  1153.  
  1154.     /*
  1155.      * Setting the select bits is a bit tricky:  if LPENDIN is set, then
  1156.      * we need to find out when the next read is done.  So, make the device
  1157.      * appear to be readable even if it isn't.  Otherwise, we won't be told
  1158.      * when the device is read.
  1159.      */
  1160.  
  1161.     done:
  1162.     *selectBitsPtr = 0;
  1163.     if ((tPtr->lastBreak != tPtr->lastRemovedIn)
  1164.         || (tPtr->localMode & LPENDIN)) {
  1165.     *selectBitsPtr |= FS_READABLE;
  1166.     }
  1167.     if (tPtr->outCharsBuffered < tPtr->cookedOutputLimit) {
  1168.     *selectBitsPtr |= FS_WRITABLE;
  1169.     }
  1170.     return result;
  1171.  
  1172.     invalid:
  1173.     if (td_Debug) {
  1174.     printf("Td_ControlCooked: command %d invalid input\n", command);
  1175.     }
  1176.     *outputSizePtr = 0;
  1177.     result = EINVAL;
  1178.     goto done;
  1179. }
  1180.  
  1181. /*
  1182.  *----------------------------------------------------------------------
  1183.  *
  1184.  * FormatInput --
  1185.  *
  1186.  *    Re-format the input buffer of an I/O control.  This is required
  1187.  *    if the client is on a host with a different byte order/alignment.
  1188.  *    This uses the Fmt_Convert library routine.
  1189.  *
  1190.  * Results:
  1191.  *    This returns zero if all goes well.
  1192.  *    Otherwise a FMT_ error code is returned.
  1193.  *
  1194.  * Side effects:
  1195.  *    The reformatted input is put into newBuffer.  The true size of
  1196.  *    the data in this buffer is returned in *newInputSizePtr.
  1197.  *
  1198.  *----------------------------------------------------------------------
  1199.  */
  1200.  
  1201. static int
  1202. FormatInput(command, format, inputSize, input, newInputSizePtr, newInput)
  1203.     int command;        /* I/O Control command */
  1204.     Fmt_Format format;        /* Format of client host */
  1205.     int inputSize;        /* Size of input buffer */
  1206.     Address input;        /* Input buffer in client format */
  1207.     int *newInputSizePtr;    /* In/Out - Size of new input buffer */
  1208.     Address newInput;        /* Out - Input buffer in our format */
  1209. {
  1210.     int status = FMT_OK;
  1211.     char *fmtString = "";
  1212.  
  1213.     switch (command) {
  1214.  
  1215.     case IOC_TTY_GET_DISCIPLINE:
  1216.     case IOC_TTY_GETP:
  1217.     case IOC_TTY_EXCL:
  1218.     case IOC_TTY_NXCL:
  1219.     case IOC_GET_OWNER:
  1220.     case IOC_TTY_GET_TCHARS:
  1221.     case IOC_TTY_GET_LM:
  1222.     case IOC_TTY_GET_LTCHARS:
  1223.     case IOC_TTY_GET_WINDOW_SIZE:
  1224.     case IOC_TTY_NOT_CONTROL_TTY:
  1225.     default:
  1226.         *newInputSizePtr = 0;
  1227.         goto noconversion;
  1228.  
  1229.     case IOC_TTY_FLUSH:
  1230.         /*
  1231.          * Optional int
  1232.          */
  1233.         if (inputSize == 0) {
  1234.         *newInputSizePtr = 0;
  1235.         goto noconversion;
  1236.         } else {
  1237.         fmtString = "w";
  1238.         }
  1239.         break;
  1240.  
  1241.     case IOC_TTY_SET_DISCIPLINE:
  1242.     case IOC_TTY_BIS_LM:
  1243.     case IOC_TTY_BIC_LM:
  1244.     case IOC_TTY_SET_LM:
  1245.         /*
  1246.          * One int
  1247.          */
  1248.         fmtString = "w";
  1249.         break;
  1250.  
  1251.     case IOC_TTY_SETP:
  1252.     case IOC_TTY_SETN:
  1253.         /*
  1254.          * struct sgttyb
  1255.          */
  1256.         fmtString = "{b4h}";
  1257.         break;
  1258.  
  1259.     case IOC_TTY_INSERT_CHAR:
  1260.         /*
  1261.          * One char
  1262.          */
  1263.         fmtString = "b";
  1264.         break;
  1265.  
  1266.     case IOC_SET_OWNER:
  1267.         /*
  1268.          * Ioc_Owner
  1269.          */
  1270.         fmtString = "{w2}";
  1271.         break;
  1272.  
  1273.     case IOC_TTY_SET_TCHARS:
  1274.         /*
  1275.          * struct tchars
  1276.          */
  1277.         fmtString = "{b6}";
  1278.         break;
  1279.  
  1280.     case IOC_TTY_SET_LTCHARS:
  1281.         /*
  1282.          * struct ltchars
  1283.          */
  1284.         fmtString = "{b6}";
  1285.         break;
  1286.  
  1287.  
  1288.     case IOC_TTY_SET_WINDOW_SIZE: {
  1289.         /*
  1290.          * struct winsize
  1291.          */
  1292.         fmtString = "{h4}";
  1293.         break;
  1294.     }
  1295.  
  1296.     }
  1297.     status = Fmt_Convert(fmtString, format, &inputSize, input, FMT_MY_FORMAT,
  1298.         newInputSizePtr, newInput);
  1299. noconversion:
  1300.     return(status);
  1301. }
  1302.  
  1303. /*
  1304.  *----------------------------------------------------------------------
  1305.  *
  1306.  * FormatOutput --
  1307.  *
  1308.  *    Re-format the output buffer of an I/O control.
  1309.  *    This uses the Fmt_Convert library routine.
  1310.  *
  1311.  * Results:
  1312.  *    This returns zero if all goes well.
  1313.  *    Otherwise a FMT_ error code is returned.
  1314.  *
  1315.  * Side effects:
  1316.  *    The reformatted output is put into newOutput.  The true size of
  1317.  *    the data in this buffer is returned in *newOutputSizePtr.
  1318.  *
  1319.  *----------------------------------------------------------------------
  1320.  */
  1321.  
  1322. static int
  1323. FormatOutput(command, format, outputSize, output, newOutputSizePtr, newOutput)
  1324.     int command;        /* I/O Control command */
  1325.     Fmt_Format format;        /* Format of client host */
  1326.     int outputSize;        /* Size of input buffer (in our format) */
  1327.     Address output;        /* Output buffer in our format */
  1328.     int *newOutputSizePtr;    /* In/Out - Size of new output buffer */
  1329.     Address newOutput;        /* Out - Output buffer in the client's format */
  1330. {
  1331.     int status = FMT_OK;
  1332.     char *fmtString = "";
  1333.  
  1334.     switch (command) {
  1335.  
  1336.     case IOC_TTY_SET_DISCIPLINE:
  1337.     case IOC_TTY_SETP:
  1338.     case IOC_TTY_SETN:
  1339.     case IOC_TTY_EXCL:
  1340.     case IOC_TTY_NXCL:
  1341.     case IOC_TTY_FLUSH:
  1342.     case IOC_TTY_INSERT_CHAR:
  1343.     case IOC_SET_OWNER:
  1344.     case IOC_TTY_SET_TCHARS:
  1345.     case IOC_TTY_BIS_LM:
  1346.     case IOC_TTY_BIC_LM:
  1347.     case IOC_TTY_SET_LM:
  1348.     case IOC_TTY_SET_LTCHARS:
  1349.     case IOC_TTY_NOT_CONTROL_TTY:
  1350.     default:
  1351.         *newOutputSizePtr = 0;
  1352.         goto noconversion;
  1353.  
  1354.     case IOC_TTY_GET_DISCIPLINE:
  1355.     case IOC_NUM_READABLE:
  1356.     case IOC_TTY_GET_LM:
  1357.     case IOC_GET_FLAGS:
  1358.         /*
  1359.          * One int
  1360.          */
  1361.         fmtString = "w";
  1362.         break;
  1363.  
  1364.     case IOC_TTY_GETP:
  1365.         /*
  1366.          * struct sgttyb
  1367.          */
  1368.         fmtString = "{b4h}";
  1369.         break;
  1370.  
  1371.     case IOC_GET_OWNER:
  1372.         /*
  1373.          * Ioc_Owner
  1374.          */
  1375.         fmtString = "{w2}";
  1376.         break;
  1377.  
  1378.     case IOC_TTY_GET_TCHARS:
  1379.         /*
  1380.          * struct tchars
  1381.          */
  1382.         fmtString = "{b6}";
  1383.         break;
  1384.  
  1385.     case IOC_TTY_GET_LTCHARS:
  1386.         /*
  1387.          * struct ltchars
  1388.          */
  1389.         fmtString = "{b6}";
  1390.         break;
  1391.  
  1392.     case IOC_TTY_GET_WINDOW_SIZE:
  1393.         /*
  1394.          * struct winsize
  1395.          */
  1396.         fmtString = "{h4}";
  1397.         break;
  1398.     }
  1399.     status = Fmt_Convert(fmtString, FMT_MY_FORMAT, &outputSize, output, format,
  1400.         newOutputSizePtr, newOutput);
  1401. noconversion:
  1402.     return(status);
  1403. }
  1404.  
  1405. /*
  1406.  *----------------------------------------------------------------------
  1407.  *
  1408.  * Td_GetRaw --
  1409.  *
  1410.  *    Retrieve characters that are ready to be output from the
  1411.  *    terminal driver to the raw device.
  1412.  *
  1413.  * Results:
  1414.  *    The return value is a count of the number of characters
  1415.  *    actually returned at buffer.  This will be less than or
  1416.  *    equal to numChars.  A return value of 0 indicates that
  1417.  *    there are no characters in terminal's output buffer or
  1418.  *    that output has been disabled.
  1419.  *
  1420.  * Side effects:
  1421.  *    Characters are removed from the terminal's output buffer,
  1422.  *    and the cooked side may be notified that the terminal is
  1423.  *    writable again.
  1424.  *
  1425.  *----------------------------------------------------------------------
  1426.  */
  1427.  
  1428. int
  1429. Td_GetRaw(terminal, numChars, buffer)
  1430.     Td_Terminal terminal;    /* Token identifying terminal. */
  1431.     int numChars;        /* Maximum number of characters to read
  1432.                  * from terminal's output buffer. */
  1433.     register char *buffer;    /* Where to place characters that are read. */
  1434. {
  1435.     register Terminal *tPtr = (Terminal *) terminal;
  1436.     int count;
  1437.  
  1438.     if (tPtr->flags & OUTPUT_OFF) {
  1439.     return 0;
  1440.     }
  1441.     for (count = 0; count < numChars; count++, buffer++) {
  1442.     if (tPtr->lastRemovedOut == tPtr->lastAddedOut) {
  1443.         break;
  1444.     }
  1445.     NEXT(tPtr->lastRemovedOut, tPtr->outBufSize, tPtr->lastRemovedOut);
  1446.     *buffer = tPtr->outputBuffer[tPtr->lastRemovedOut];
  1447.     }
  1448.     tPtr->outCharsBuffered -= count;
  1449.     if (tPtr->outCharsBuffered < tPtr->cookedOutputLimit) {
  1450.     (*tPtr->cookedProc)(tPtr->cookedData, TD_COOKED_WRITES_OK,
  1451.         0, (char *) NULL, 0, (char *) NULL);
  1452.     }
  1453.     return count;
  1454. }
  1455.  
  1456. /*
  1457.  *----------------------------------------------------------------------
  1458.  *
  1459.  * Td_PutRaw --
  1460.  *
  1461.  *    This procedure is invoked when characters arrive from the
  1462.  *    raw device associated with the terminal (e.g., from the
  1463.  *    keyboard).  It adds them to the input buffer of the terminal
  1464.  *    and does appropriate line editing etc.
  1465.  *
  1466.  * Results:
  1467.  *    None.
  1468.  *
  1469.  * Side effects:
  1470.  *    Characters are added to the input buffer, and may be made
  1471.  *    available on the cooked side of the terminal.  Echoed
  1472.  *    characters get added to the output buffer, which could result
  1473.  *    in a call to the raw control procedure.
  1474.  *
  1475.  *----------------------------------------------------------------------
  1476.  */
  1477.  
  1478. void
  1479. Td_PutRaw(terminal, numChars, buffer)
  1480.     Td_Terminal terminal;    /* Token identifying terminal. */
  1481.     int numChars;        /* Number of characters to process. */
  1482.     char *buffer;        /* Characters that were ostensibly typed
  1483.                  * on the raw device's keyboard. */
  1484. {
  1485.     register Terminal *tPtr = (Terminal *) terminal;
  1486.     int next, oldCharsBuffered;
  1487.     register char c = '\0';    /* dummy initial value */
  1488.     Td_Signal signalInfo;
  1489.  
  1490.     oldCharsBuffered = tPtr->outCharsBuffered;
  1491.     tPtr->localMode &= ~LFLUSHO;
  1492.  
  1493.     /*
  1494.      * According to the 4.3 BSD manual page, we should re-echo everything
  1495.      * in the input buffer if LPENDIN is set here.  But this appears to
  1496.      * produce the wrong results and I suspect that it isn't even
  1497.      * implemented in BSD.  So it's not implemented here either.
  1498.      */
  1499.  
  1500.     for ( ; numChars > 0; numChars--, buffer++) {
  1501.     c = *buffer;
  1502.  
  1503.     /*
  1504.      * Skip all further processing if in raw mode.
  1505.      */
  1506.     
  1507.     if (tPtr->sgttyb.sg_flags & RAW) {
  1508.         goto addToBuffer;
  1509.     }
  1510.     c &= 0x7f;
  1511.  
  1512.     /*
  1513.      * Handle flow-control characters.
  1514.      */
  1515.  
  1516.     
  1517.     if (c == tPtr->tchars.t_stopc) {
  1518.         if (tPtr->flags & OUTPUT_OFF) {
  1519.         if (c == tPtr->tchars.t_startc) {
  1520.             goto restartOutput;
  1521.         }
  1522.         } else {
  1523.         tPtr->flags |= OUTPUT_OFF;
  1524.         }
  1525.         continue;
  1526.     } else if (c == tPtr->tchars.t_startc) {
  1527.         restartOutput:
  1528.         tPtr->flags &= ~OUTPUT_OFF;
  1529.         if (tPtr->outCharsBuffered != 0) {
  1530.         (*tPtr->rawProc)(tPtr->rawData, TD_RAW_OUTPUT_READY,
  1531.             0, (char *) NULL, 0, (char *) NULL);
  1532.         }
  1533.         continue;
  1534.     } else if ((tPtr->flags & OUTPUT_OFF) && !(tPtr->localMode & LDECCTQ)) {
  1535.         tPtr->flags &= ~OUTPUT_OFF;
  1536.         if (tPtr->outCharsBuffered != 0) {
  1537.         (*tPtr->rawProc)(tPtr->rawData, TD_RAW_OUTPUT_READY,
  1538.             0, (char *) NULL, 0, (char *) NULL);
  1539.         }
  1540.     }
  1541.  
  1542.     /*
  1543.      * If the last character typed was a "quote" character, then
  1544.      * just add the new character to the input buffer without
  1545.      * additional processing.
  1546.      */
  1547.  
  1548.     if (tPtr->flags & LITERAL_NEXT) {
  1549.         tPtr->flags &= ~LITERAL_NEXT;
  1550.         goto addToBuffer;
  1551.     }
  1552.  
  1553.     /*
  1554.      * Handle output-flushing character.  Clearing oldCharsBuffered
  1555.      * is essential, otherwise, the raw client won't be notified if
  1556.      * characters are added to the output buffer in this procedure.
  1557.      */
  1558.  
  1559.     if (c == tPtr->ltchars.t_flushc) {
  1560.         if (tPtr->localMode & LFLUSHO) {
  1561.         tPtr->localMode &= ~LFLUSHO;
  1562.         } else {
  1563.         TdFlushOutput(tPtr);
  1564.         oldCharsBuffered = 0;
  1565.         TdEcho(tPtr, c);
  1566.         TdRetypeInput(tPtr, tPtr->lastRemovedIn);
  1567.         tPtr->localMode |= LFLUSHO;
  1568.         }
  1569.         continue;
  1570.     }
  1571.     
  1572.     /*
  1573.      * Handle line-editing characters such as erase and kill.
  1574.      */
  1575.     
  1576.     if ((c == '\r') && (tPtr->sgttyb.sg_flags & CRMOD)) {
  1577.         c = '\n';
  1578.     }
  1579.     if (!(tPtr->sgttyb.sg_flags & CBREAK)) {
  1580.         if (c == tPtr->sgttyb.sg_erase) {        /* Backspace. */
  1581.         if (tPtr->lastAddedIn != tPtr->lastBreak) {
  1582.             TdBackspace(tPtr);
  1583.         }
  1584.         continue;
  1585.         } else if (c == tPtr->ltchars.t_werasc) {    /* Delete word. */
  1586.         int gotNonSpace = 0;
  1587.     
  1588.         while (tPtr->lastAddedIn != tPtr->lastBreak) {
  1589.             if (isspace(tPtr->inputBuffer[tPtr->lastAddedIn])) {
  1590.             if (gotNonSpace) {
  1591.                 break;
  1592.             }
  1593.             } else {
  1594.             gotNonSpace = 1;
  1595.             }
  1596.             TdBackspace(tPtr);
  1597.         }
  1598.         continue;
  1599.         } else if (c == tPtr->sgttyb.sg_kill) {    /* Delete line. */
  1600.         if ((tPtr->lastHidden != -1) || !(tPtr->localMode & LCRTKIL)) {
  1601.             TdEcho(tPtr, c);
  1602.             TdEcho(tPtr, '\n');
  1603.             tPtr->lastAddedIn = tPtr->lastBreak;
  1604.             tPtr->lastHidden = -1;
  1605.         } else {
  1606.             while (tPtr->lastAddedIn != tPtr->lastBreak) {
  1607.             TdBackspace(tPtr);
  1608.             }
  1609.         }
  1610.         continue;
  1611.         } else if (c == tPtr->ltchars.t_rprntc) {    /* Re-echo all. */
  1612.         TdEcho(tPtr, c);
  1613.         TdEcho(tPtr, '\n');
  1614.         TdRetypeInput(tPtr, tPtr->lastRemovedIn);
  1615.         continue;
  1616.         }
  1617.     }
  1618.  
  1619.     if (c == tPtr->ltchars.t_lnextc) {
  1620.         tPtr->flags |= LITERAL_NEXT;
  1621.         continue;
  1622.     }
  1623.     
  1624.     /*
  1625.      * Generate signals in response to certain input characters.  If this
  1626.      * isn't a signal character, then officially add it to the input
  1627.      * buffer.
  1628.      */
  1629.     
  1630.     if (c == tPtr->tchars.t_intrc) {
  1631.         signalInfo.sigNum = SIGINT;
  1632.         sendSignal:
  1633.         signalInfo.groupID = tPtr->owner;
  1634.         (*tPtr->cookedProc)(tPtr->cookedData, TD_COOKED_SIGNAL,
  1635.             sizeof(signalInfo), (char *) &signalInfo,
  1636.             0, (char *) NULL);
  1637.         TdFlushInput(tPtr);
  1638.         TdFlushOutput(tPtr);
  1639.         oldCharsBuffered = 0;
  1640.         goto echo;
  1641.     } else if (c == tPtr->tchars.t_quitc) {
  1642.         signalInfo.sigNum = SIGQUIT;
  1643.         goto sendSignal;
  1644.     } else if (c == tPtr->ltchars.t_suspc) {
  1645.         signalInfo.sigNum = SIGTSTP;
  1646.         goto sendSignal;
  1647.     }
  1648.     
  1649.     /*
  1650.      * If the buffer is full, then reallocate it with a size twice as
  1651.      * large.  Then add the character to the buffer.
  1652.      */
  1653.     
  1654.     addToBuffer:
  1655.     NEXT(tPtr->lastAddedIn, tPtr->inBufSize, next);
  1656.     if (next == tPtr->lastRemovedIn) {
  1657.         char *newBuffer;
  1658.         int src, dst;
  1659.     
  1660.         newBuffer = malloc((unsigned) 2*tPtr->inBufSize);
  1661.         for (src = tPtr->lastRemovedIn, dst = 0; src != tPtr->lastAddedIn; ) {
  1662.         NEXT(src, tPtr->inBufSize, src);
  1663.         dst += 1;
  1664.         newBuffer[dst] = tPtr->inputBuffer[src];
  1665.         }
  1666.         tPtr->lastBreak -= tPtr->lastRemovedIn;
  1667.         if (tPtr->lastBreak < 0) {
  1668.         tPtr->lastBreak += tPtr->inBufSize;
  1669.         }
  1670.         if (tPtr->lastHidden != -1) {
  1671.         tPtr->lastHidden -= tPtr->lastRemovedIn;
  1672.         if (tPtr->lastHidden < 0) {
  1673.             tPtr->lastHidden += tPtr->inBufSize;
  1674.         }
  1675.         }
  1676.         tPtr->inputBuffer = newBuffer;
  1677.         tPtr->inBufSize *= 2;
  1678.         tPtr->lastRemovedIn = 0;
  1679.         tPtr->lastAddedIn = dst;
  1680.         NEXT(dst, tPtr->inBufSize, next);
  1681.     }
  1682.     tPtr->inputBuffer[next] = c;
  1683.     tPtr->lastAddedIn = next;
  1684.     
  1685.     /*
  1686.      * Echo.
  1687.      */
  1688.     
  1689.     echo:
  1690.     if ((tPtr->sgttyb.sg_flags & ECHO) && !(tPtr->sgttyb.sg_flags & RAW)) {
  1691.         if (tPtr->flags & BS_IN_PROGRESS) {
  1692.         TdPutChar(tPtr, '/');
  1693.         tPtr->flags &= ~BS_IN_PROGRESS;
  1694.         }
  1695.         TdEcho(tPtr, c);
  1696.     }
  1697.     }
  1698.  
  1699.     /*
  1700.      * Are there any characters that are ready for reading?  If so,
  1701.      * change the terminal's state to be readable and notify the
  1702.      * cooked side.
  1703.      */
  1704.  
  1705.     if ((tPtr->sgttyb.sg_flags & (RAW|CBREAK)) || (c == tPtr->tchars.t_eofc) ||
  1706.         (c == tPtr->tchars.t_brkc) || (c == '\n')) {
  1707.     tPtr->lastBreak = tPtr->lastAddedIn;
  1708.     tPtr->lastHidden = -1;
  1709.     tPtr->keyIndex = tPtr->lastAddedIn;
  1710.     tPtr->keyColumn = tPtr->column;
  1711.     (*tPtr->cookedProc)(tPtr->cookedData, TD_COOKED_READS_OK,
  1712.         0, (char *) NULL, 0, (char *) NULL);
  1713.     }
  1714.  
  1715.     /*
  1716.      * If the output buffer just became non-empty, then notify the
  1717.      * raw control procedure.
  1718.      */
  1719.  
  1720.     if ((oldCharsBuffered == 0) && (tPtr->outCharsBuffered != 0) &&
  1721.         !(tPtr->flags & OUTPUT_OFF)) {
  1722.     (*tPtr->rawProc)(tPtr->rawData, TD_RAW_OUTPUT_READY,
  1723.         0, (char *) NULL, 0, (char *) NULL);
  1724.     }
  1725. }
  1726.  
  1727. /*
  1728.  *----------------------------------------------------------------------
  1729.  *
  1730.  * Td_ControlRaw --
  1731.  *
  1732.  *    This procedure is used to tell the terminal driver that
  1733.  *    certain special things happened on the raw side of the
  1734.  *    terminal, such as a hangup or break.
  1735.  *
  1736.  * Results:
  1737.  *    None.
  1738.  *
  1739.  * Side effects:
  1740.  *    Depends on the operation;  see the man page for details
  1741.  *    on what commands may be invoked.
  1742.  *
  1743.  *----------------------------------------------------------------------
  1744.  */
  1745.  
  1746.     /* ARGSUSED */
  1747. void
  1748. Td_ControlRaw(terminal, operation)
  1749.     Td_Terminal terminal;        /* Token for terminal. */
  1750.     int operation;            /* What just happened: TD_BREAK etc. */
  1751. {
  1752.     register Terminal *tPtr = (Terminal *) terminal;
  1753.  
  1754.     switch (operation) {
  1755.     case TD_BREAK: {
  1756.  
  1757.         /*
  1758.          * Reset some of the terminal state, such as flow control,
  1759.          * then pretend an interrupt character was typed.
  1760.          */
  1761.  
  1762.         tPtr->flags &= ~(OUTPUT_OFF | BS_IN_PROGRESS | LITERAL_NEXT);
  1763.         if (tPtr->sgttyb.sg_flags & RAW) {
  1764.         char c = 0;
  1765.         Td_PutRaw(terminal, 1, &c);
  1766.         } else if ((int) tPtr->tchars.t_intrc != -1) {
  1767.         Td_PutRaw(terminal, 1, &tPtr->tchars.t_intrc);
  1768.         }
  1769.         if (tPtr->outCharsBuffered != 0) {
  1770.         (*tPtr->rawProc)(tPtr->rawData, TD_RAW_OUTPUT_READY,
  1771.             0, (char *) NULL, 0, (char *) NULL);
  1772.         }
  1773.         break;
  1774.     }
  1775.     }
  1776. }
  1777.  
  1778. /*
  1779.  *----------------------------------------------------------------------
  1780.  *
  1781.  * TdPutChar --
  1782.  *
  1783.  *    Add a character to the output buffer associated with a
  1784.  *    terminal, and keep track of the current column while outputting
  1785.  *    the character.  This routine also substitutes spaces for tabs,
  1786.  *    if that's the mode the terminal is in.
  1787.  *
  1788.  * Results:
  1789.  *    None.
  1790.  *
  1791.  * Side effects:
  1792.  *    TPtr->column gets updated and stuff gets added to the terminal's
  1793.  *    output buffer.  The output buffer will get grown if necessary.
  1794.  *
  1795.  *----------------------------------------------------------------------
  1796.  */
  1797.  
  1798. static void
  1799. TdPutChar(tPtr, c)
  1800.     register Terminal *tPtr;    /* Terminal on which to output. */
  1801.     char c;            /* Character to output. */
  1802. {
  1803.     /*
  1804.      * Ignore the character if output is being flushed.
  1805.      */
  1806.  
  1807.     if (tPtr->localMode & LFLUSHO) {
  1808.     return;
  1809.     }
  1810.  
  1811.     /*
  1812.      * Grow the output buffer if there isn't enough space for the
  1813.      * largest amount of information this procedure might want to
  1814.      * add to it.
  1815.      */
  1816.  
  1817.     if ((tPtr->outCharsBuffered + 8) >= tPtr->outBufSize) {
  1818.     char *newBuffer;
  1819.     int dst;
  1820.  
  1821.     newBuffer = malloc((unsigned) (2*tPtr->outBufSize));
  1822.     for (dst = 0; tPtr->lastRemovedOut != tPtr->lastAddedOut; ) {
  1823.         dst += 1;
  1824.         NEXT(tPtr->lastRemovedOut, tPtr->outBufSize, tPtr->lastRemovedOut);
  1825.         newBuffer[dst] = tPtr->outputBuffer[tPtr->lastRemovedOut];
  1826.     }
  1827.     tPtr->outputBuffer = newBuffer;
  1828.     tPtr->outBufSize *= 2;
  1829.     tPtr->lastRemovedOut = 0;
  1830.     tPtr->lastAddedOut = dst;
  1831.     }
  1832.  
  1833.     /*
  1834.      * Update column position, and add character(s) to the buffer.
  1835.      */
  1836.  
  1837.     if (isprint(c)) {
  1838.     tPtr->column += 1;
  1839.     } else if (c == '\r') {
  1840.     tPtr->column = 0;
  1841.     } else if (c == '\t') {
  1842.     int count = 8 - (tPtr->column & 07);
  1843.  
  1844.     tPtr->column += count;
  1845.     if ((tPtr->sgttyb.sg_flags & TBDELAY) == XTABS) {
  1846.         for ( ; count > 0; count--) {
  1847.         NEXT(tPtr->lastAddedOut, tPtr->outBufSize, tPtr->lastAddedOut);
  1848.         tPtr->outputBuffer[tPtr->lastAddedOut] = ' ';
  1849.         tPtr->outCharsBuffered++;
  1850.         }
  1851.         return;
  1852.     }
  1853.     } else if (c == '\b') {
  1854.     tPtr->column -= 1;
  1855.     }
  1856.     NEXT(tPtr->lastAddedOut, tPtr->outBufSize, tPtr->lastAddedOut);
  1857.     tPtr->outputBuffer[tPtr->lastAddedOut] = c;
  1858.     tPtr->outCharsBuffered++;
  1859. }
  1860.  
  1861. /*
  1862.  *----------------------------------------------------------------------
  1863.  *
  1864.  * TdEcho --
  1865.  *
  1866.  *    Echo a character on a terminal, if echoing is enabled.
  1867.  *
  1868.  * Results:
  1869.  *    None.
  1870.  *
  1871.  * Side effects:
  1872.  *    The appropriate echo sequence for c gets added to the 
  1873.  *    terminal's output buffer.
  1874.  *
  1875.  *----------------------------------------------------------------------
  1876.  */
  1877.  
  1878. static void
  1879. TdEcho(tPtr, c)
  1880.     register Terminal *tPtr;    /* Terminal for which to echo. */
  1881.     register char c;        /* Character to echo. */
  1882. {
  1883.     if (!(tPtr->sgttyb.sg_flags & ECHO)) {
  1884.     return;
  1885.     }
  1886.     if (isprint(c)) {
  1887.     TdPutChar(tPtr, c);
  1888.     } else if (c == '\n') {
  1889.     if (tPtr->sgttyb.sg_flags & CRMOD) {
  1890.         TdPutChar(tPtr, '\r');
  1891.     }
  1892.     TdPutChar(tPtr, '\n');
  1893.     } else if (c == '\t') {
  1894.     TdPutChar(tPtr, c);
  1895.     } else if (c == 04) {
  1896.     /* Don't echo control-D's. */
  1897.     } else if (tPtr->localMode & LCTLECH) {
  1898.     TdPutChar(tPtr, '^');
  1899.     if (c == 0177) {
  1900.         TdPutChar(tPtr, '?');
  1901.     } else {
  1902.         TdPutChar(tPtr, c + 'A' - 1);
  1903.     }
  1904.     } else {
  1905.     TdPutChar(tPtr, c);
  1906.     }
  1907. }
  1908.  
  1909. /*
  1910.  *----------------------------------------------------------------------
  1911.  *
  1912.  * TdRetypeInput --
  1913.  *
  1914.  *    This procedure is called to re-echo all of the characters in
  1915.  *    the input buffer.
  1916.  *
  1917.  * Results:
  1918.  *    None.
  1919.  *
  1920.  * Side effects:
  1921.  *    Characters get added to the terminal's output buffer.
  1922.  *
  1923.  *----------------------------------------------------------------------
  1924.  */
  1925.  
  1926. static void
  1927. TdRetypeInput(tPtr, start)
  1928.     register Terminal *tPtr;    /* Which terminal to re-echo for. */
  1929.     int start;            /* Index within tPtr's buffer:  start
  1930.                  * echoing at the character AFTER this one. */
  1931. {
  1932.     tPtr->keyIndex = start;
  1933.     tPtr->keyColumn = tPtr->column;
  1934.     while (start != tPtr->lastAddedIn) {
  1935.     NEXT(start, tPtr->inBufSize, start);
  1936.     TdEcho(tPtr, tPtr->inputBuffer[start]);
  1937.     }
  1938.     tPtr->lastHidden = -1;
  1939. }
  1940.  
  1941. /*
  1942.  *----------------------------------------------------------------------
  1943.  *
  1944.  * TdBackspace --
  1945.  *
  1946.  *    Using mode information from tPtr, output the appropriate
  1947.  *    sequence to backspace over the most recently typed character
  1948.  *    in tPtr's input buffer.  Also remove the character from
  1949.  *    the input buffer.
  1950.  *
  1951.  * Results:
  1952.  *    None.
  1953.  *
  1954.  * Side effects:
  1955.  *    TPtr's input buffer ends up with less characters in it,
  1956.  *    and stuff gets added to the output buffer.
  1957.  *
  1958.  *----------------------------------------------------------------------
  1959.  */
  1960.  
  1961. static void
  1962. TdBackspace(tPtr)
  1963.     register Terminal *tPtr;        /* Terminal to backspace. */
  1964. {
  1965.     if (tPtr->sgttyb.sg_flags & ECHO) {
  1966.     if (tPtr->localMode & LCRTBS) {
  1967.         int count;
  1968.         char c;
  1969.  
  1970.         /*
  1971.          * CRT-style backspacing:  the character can actually be erased.
  1972.          * Figure out how wide the character was, then back over it one
  1973.          * space at a time.  If there's output intervening between us and
  1974.          * the next character to erase, then first re-echo everything.
  1975.          */
  1976.  
  1977.         if (tPtr->lastAddedIn == tPtr->lastHidden) {
  1978.         c = tPtr->ltchars.t_rprntc;
  1979.         if ((c & 0377) == 0377) {
  1980.             c = ltcharsDefault.t_rprntc;
  1981.         }
  1982.         TdEcho(tPtr, c);
  1983.         TdEcho(tPtr, '\n');
  1984.         TdRetypeInput(tPtr, tPtr->lastRemovedIn);
  1985.         tPtr->lastHidden = -1;
  1986.         }
  1987.         c = tPtr->inputBuffer[tPtr->lastAddedIn];
  1988.         if (isprint(c)) {
  1989.         count = 1;
  1990.         } else {
  1991.         int i, pos;
  1992.         char c2;
  1993.  
  1994.         /*
  1995.          * Anything besides a normal printing character is tricky.  Tabs
  1996.          * are particularly nasty.  To figure out how much to erase,
  1997.          * work forwards from a known position, computing the position
  1998.          * of the character just before the one being erased.
  1999.          */
  2000.  
  2001.         i = tPtr->keyIndex;
  2002.         pos = tPtr->keyColumn;
  2003.         while (TRUE) {
  2004.             NEXT(i, tPtr->inBufSize, i);
  2005.             if (i == tPtr->lastAddedIn) {
  2006.             break;
  2007.             }
  2008.             c2 = tPtr->inputBuffer[i];
  2009.             if (isprint(c2)) {
  2010.             pos++;
  2011.             } else if (c2 == '\t') {
  2012.             pos = (pos + 8) & ~07;
  2013.             } else if (((c2 == '\n') && !(tPtr->sgttyb.sg_flags & CRMOD))
  2014.                 || (c2 == 04)) {
  2015.             /* No change to position. */
  2016.             } else if (tPtr->localMode & LCTLECH) {
  2017.             pos += 2;
  2018.             } else if (c2 == '\b') {
  2019.             pos -= 1;
  2020.             }
  2021.         }
  2022.         count = tPtr->column - pos;
  2023.         }
  2024.  
  2025.         for ( ; count > 0; count--) {
  2026.         if (tPtr->localMode & LCRTERA) {
  2027.             TdPutChar(tPtr, '\b');
  2028.             TdPutChar(tPtr, ' ');
  2029.         }
  2030.         TdPutChar(tPtr, '\b');
  2031.         }
  2032.     } else if (tPtr->localMode & LPRTERA) {
  2033.  
  2034.         /*
  2035.          * Hardcopy terminal:  backspace by outputting erased characters
  2036.          * between "\" and "/" delimiters.
  2037.          */
  2038.  
  2039.         if (!(tPtr->flags & BS_IN_PROGRESS)) {
  2040.         TdPutChar(tPtr, '\\');
  2041.         tPtr->flags |= BS_IN_PROGRESS;
  2042.         }
  2043.         TdEcho(tPtr, tPtr->inputBuffer[tPtr->lastAddedIn]);
  2044.     } else {
  2045.  
  2046.         /*
  2047.          * Old-style backspace:  just echo the backspace character.
  2048.          */
  2049.  
  2050.         TdEcho(tPtr, tPtr->sgttyb.sg_erase);
  2051.     }
  2052.     }
  2053.     PREV(tPtr->lastAddedIn, tPtr->inBufSize, tPtr->lastAddedIn);
  2054. }
  2055.  
  2056. /*
  2057.  *----------------------------------------------------------------------
  2058.  *
  2059.  * TdFlushInput --
  2060.  *
  2061.  *    Empty the input buffer associated with a terminal.
  2062.  *
  2063.  * Results:
  2064.  *    None.
  2065.  *
  2066.  * Side effects:
  2067.  *    TPtr's input buffer is cleared.
  2068.  *
  2069.  *----------------------------------------------------------------------
  2070.  */
  2071.  
  2072. static void
  2073. TdFlushInput(tPtr)
  2074.     register Terminal *tPtr;        /* Terminal to flush. */
  2075. {
  2076.     tPtr->lastAddedIn = tPtr->lastRemovedIn = 0;
  2077.     tPtr->lastBreak = tPtr->keyIndex = 0;
  2078.     tPtr->lastHidden = -1;
  2079.     tPtr->keyColumn = tPtr->column;
  2080.     tPtr->flags &= ~(LITERAL_NEXT|BS_IN_PROGRESS);
  2081. }
  2082.  
  2083. /*
  2084.  *----------------------------------------------------------------------
  2085.  *
  2086.  * TdFlushOutput --
  2087.  *
  2088.  *    Empty the output queue for a terminal.
  2089.  *
  2090.  * Results:
  2091.  *    None.
  2092.  *
  2093.  * Side effects:
  2094.  *    The output buffer for tPtr is emptied, and the terminal's raw
  2095.  *    control procedure is invoked to empty any other buffers down
  2096.  *    the line.  The cooked side gets notified that the terminal
  2097.  *    is now writable.
  2098.  *
  2099.  *----------------------------------------------------------------------
  2100.  */
  2101.  
  2102. static void
  2103. TdFlushOutput(tPtr)
  2104.     register Terminal *tPtr;        /* Terminal to flush. */
  2105. {
  2106.     tPtr->lastAddedOut = tPtr->lastRemovedOut = 0;
  2107.     tPtr->outCharsBuffered = 0;
  2108.     (*tPtr->rawProc)(tPtr->rawData, TD_RAW_FLUSH_OUTPUT, 0,
  2109.         (char *) NULL, 0, (char *) NULL);
  2110.     (*tPtr->cookedProc)(tPtr->cookedData, TD_COOKED_WRITES_OK, 0,
  2111.         (char *) NULL, 0, (char *) NULL);
  2112. }
  2113. @
  2114.  
  2115.  
  2116. 1.20.1.1
  2117. log
  2118. @Initial branch for Sprite server.
  2119. @
  2120. text
  2121. @d21 1
  2122. a21 1
  2123. static char rcsid[] = "$Header: /sprite/src/lib/c/etc/RCS/ttyDriver.c,v 1.20 92/03/18 16:33:08 rab Exp $ SPRITE (Berkeley)";
  2124. @
  2125.  
  2126.  
  2127. 1.19
  2128. log
  2129. @Use function prototypes.  Lint.
  2130. @
  2131. text
  2132. @d21 1
  2133. a21 1
  2134. static char rcsid[] = "$Header: /sprite/src/lib/c/etc/RCS/ttyDriver.c,v 1.18 90/09/05 18:56:18 rab Exp Locker: kupfer $ SPRITE (Berkeley)";
  2135. d1643 1
  2136. a1643 1
  2137.         } else if (tPtr->tchars.t_intrc != -1) {
  2138. @
  2139.  
  2140.  
  2141. 1.18
  2142. log
  2143. @Add prototypes.
  2144. @
  2145. text
  2146. @d21 1
  2147. a21 1
  2148. static char rcsid[] = "$Header: /sprite/src/lib/c/etc/RCS/ttyDriver.c,v 1.17 90/06/27 11:16:52 shirriff Exp Locker: rab $ SPRITE (Berkeley)";
  2149. d24 1
  2150. d130 4
  2151. a133 1
  2152.     int (*cookedProc)();    /* Procedure to call to register change
  2153. d136 4
  2154. a139 1
  2155.     int (*rawProc)();        /* Procedure to call to register change
  2156. d206 13
  2157. a218 10
  2158. static void TdBackspace _ARGS_((register Terminal *tPtr));
  2159. static void TdEcho _ARGS_((register Terminal *tPtr, register char c));
  2160. static void TdFlushInput _ARGS_((register Terminal *tPtr));
  2161. static void TdFlushOutput _ARGS_((register Terminal *tPtr));
  2162. static void TdPutChar _ARGS_((register Terminal *tPtr, char c));
  2163. static void TdRetypeInput _ARGS_((register Terminal *tPtr, int start));
  2164. static int FormatInput _ARGS_((int command, Fmt_Format format, int inputSize,
  2165.     char *input, int *newInputSizePtr, char *newInput));
  2166. static int FormatOutput _ARGS_((int command, Fmt_Format format, int outputSize,
  2167.     char *output, int *newOutputSizePtr, char *newOutput));
  2168. d245 4
  2169. a248 1
  2170.     int (*cookedProc)();    /* Procedure to call for control operations
  2171. d253 4
  2172. a256 1
  2173.     int (*rawProc)();        /* Procedure to call for control operations
  2174. d672 1
  2175. a672 1
  2176.     char *out;
  2177. d691 1
  2178. a691 1
  2179.     InBuf newInputBuf, newOutputBuf;
  2180. d704 1
  2181. a704 1
  2182.                 &newSize, &newInputBuf) != FMT_OK) {
  2183. d1083 1
  2184. a1083 1
  2185.     char *input;        /* Input buffer in client format */
  2186. d1085 1
  2187. a1085 1
  2188.     char *newInput;        /* Out - Input buffer in our format */
  2189. d1204 1
  2190. a1204 1
  2191.     char *output;        /* Output buffer in our format */
  2192. d1206 1
  2193. a1206 1
  2194.     char *newOutput;        /* Out - Output buffer in the client's format */
  2195. d1364 1
  2196. a1364 1
  2197.     register char c;
  2198. a1632 1
  2199.         Td_Signal signalInfo;
  2200. @
  2201.  
  2202.  
  2203. 1.17
  2204. log
  2205. @Added IOC_TTY_NOT_CONTROL_TTY.
  2206. @
  2207. text
  2208. @d21 1
  2209. a21 1
  2210. static char rcsid[] = "$Header: /sprite/src/lib/c/etc/RCS/ttyDriver.c,v 1.16 90/02/28 11:10:06 brent Exp $ SPRITE (Berkeley)";
  2211. d199 11
  2212. a209 8
  2213. extern void        TdBackspace();
  2214. extern void        TdEcho();
  2215. extern void        TdFlushInput();
  2216. extern void        TdFlushOutput();
  2217. extern void        TdPutChar();
  2218. extern void        TdRetypeInput();
  2219. static int        FormatInput();
  2220. static int        FormatOutput();
  2221. d1660 1
  2222. a1660 1
  2223. void
  2224. d1740 1
  2225. a1740 1
  2226. void
  2227. d1788 1
  2228. a1788 1
  2229. void
  2230. d1823 1
  2231. a1823 1
  2232. void
  2233. d1831 1
  2234. a1831 1
  2235.     
  2236. d1838 1
  2237. a1838 1
  2238.     
  2239. d1855 1
  2240. a1855 1
  2241.     
  2242. d1862 1
  2243. a1862 1
  2244.     
  2245. d1886 1
  2246. a1886 1
  2247.     
  2248. d1895 1
  2249. a1895 1
  2250.     
  2251. d1900 1
  2252. a1900 1
  2253.     
  2254. d1907 1
  2255. a1907 1
  2256.     
  2257. d1934 1
  2258. a1934 1
  2259. void
  2260. d1964 1
  2261. a1964 1
  2262. void
  2263. @
  2264.  
  2265.  
  2266. 1.16
  2267. log
  2268. @Added byteswapping for I/O controls.
  2269. Fixed handling of IOC_TTY_FLUSH so it pays attention to the
  2270. FREAD|FWRITE argument
  2271. @
  2272. text
  2273. @d21 1
  2274. a21 1
  2275. static char rcsid[] = "$Header: /sprite/src/lib/c/etc/RCS/ttyDriver.c,v 1.15 90/02/08 13:42:09 ouster Exp Locker: brent $ SPRITE (Berkeley)";
  2276. d925 1
  2277. d1082 1
  2278. d1207 1
  2279. @
  2280.  
  2281.  
  2282. 1.15
  2283. log
  2284. @Generate SIGWINCH signal when window size changes.
  2285. @
  2286. text
  2287. @d21 1
  2288. a21 1
  2289. static char rcsid[] = "$Header: /sprite/src/lib/c/etc/RCS/ttyDriver.c,v 1.14 89/07/28 16:04:40 ouster Exp Locker: ouster $ SPRITE (Berkeley)";
  2290. d32 1
  2291. d193 2
  2292. d205 2
  2293. d628 1
  2294. a628 1
  2295. Td_ControlCooked(terminal, command, inputSize, input, outputSizePtr,
  2296. d632 2
  2297. a633 1
  2298.                      * (e.g. TIOCGETP). */
  2299. d672 1
  2300. d675 16
  2301. d770 23
  2302. a792 3
  2303.     case IOC_TTY_FLUSH:
  2304.         if (inputSize != 0) {
  2305.         goto invalid;
  2306. a793 2
  2307.         TdFlushInput(tPtr);
  2308.         TdFlushOutput(tPtr);
  2309. d795 1
  2310. a795 1
  2311.  
  2312. d952 7
  2313. a958 4
  2314.  
  2315.     if (count < *outputSizePtr) {
  2316.     count = *outputSizePtr;
  2317.     }
  2318. d960 11
  2319. a970 1
  2320.     bcopy(out, output, count);
  2321. a971 2
  2322.     *outputSizePtr = count;
  2323.     result = 0;
  2324. d1030 3
  2325. d1036 222
  2326. @
  2327.  
  2328.  
  2329. 1.14
  2330. log
  2331. @Implemented DECCTLQ (and its absence) correctly.
  2332. @
  2333. text
  2334. @d21 1
  2335. a21 1
  2336. static char rcsid[] = "$Header: /sprite/src/lib/c/etc/RCS/ttyDriver.c,v 1.13 89/07/19 08:58:37 ouster Exp $ SPRITE (Berkeley)";
  2337. d894 2
  2338. a895 1
  2339.     case IOC_TTY_SET_WINDOW_SIZE:
  2340. d900 5
  2341. d906 1
  2342. @
  2343.  
  2344.  
  2345. 1.13
  2346. log
  2347. @Various changes made to use in kernel:  baud-rate changes, break
  2348. characters, default owner of "anyone".
  2349. @
  2350. text
  2351. @d21 1
  2352. a21 1
  2353. static char rcsid[] = "$Header: /sprite/src/lib/c/etc/RCS/ttyDriver.c,v 1.12 89/06/03 16:46:20 ouster Exp $ SPRITE (Berkeley)";
  2354. d1087 1
  2355. d1105 6
  2356. @
  2357.  
  2358.  
  2359. 1.12
  2360. log
  2361. @Several changes:  TD_HANGUP is now TD_GOT_CARRIER and TD_LOST_CARRIER,
  2362. added TD_RAW_BAUD_RATE callback, changed TD_COOKED_SIGNAL to provide
  2363. both signal number and controlling process group.
  2364. @
  2365. text
  2366. @d21 1
  2367. a21 1
  2368. static char rcsid[] = "$Header: /sprite/src/lib/c/etc/RCS/ttyDriver.c,v 1.11 89/04/20 10:24:35 ouster Exp Locker: ouster $ SPRITE (Berkeley)";
  2369. d239 1
  2370. d248 1
  2371. a248 1
  2372.     tPtr->owner = 0;
  2373. d269 10
  2374. d444 1
  2375. a444 1
  2376.     if (pID != tPtr->owner) {
  2377. d451 1
  2378. a451 1
  2379.     } else if (familyID != tPtr->owner) {
  2380. d921 1
  2381. a921 1
  2382.     Td_BaudRate baud;
  2383. d925 11
  2384. a935 2
  2385.     (*tPtr->rawProc)(tPtr->rawData, TD_RAW_BAUD_RATE,
  2386.         sizeof(baud), (char *) &baud, 0, (char *) NULL);
  2387. d1081 1
  2388. d1107 3
  2389. a1109 1
  2390.      * Skip line-editing and output-flushing stuff if in cbreak mode.
  2391. a1122 1
  2392.     c &= 0177;
  2393. d1316 25
  2394. a1340 3
  2395.     /*
  2396.      * Not yet implemented...
  2397.      */
  2398. @
  2399.  
  2400.  
  2401. 1.11
  2402. log
  2403. @Flush buffer on signals.  Also fixed WRITES_OK info to be consistent
  2404. (some places did it when buffer empty, others when below threshold;
  2405. this caused wakeups to get missed in some situations).
  2406. @
  2407. text
  2408. @d21 1
  2409. a21 1
  2410. static char rcsid[] = "$Header: /a/newcmds/tty/RCS/ttyDriver.c,v 1.5 89/03/23 15:26:16 ouster Exp Locker: ouster $ SPRITE (Berkeley)";
  2411. d297 2
  2412. d639 1
  2413. a639 1
  2414.     Td_FlowChars flow;
  2415. d657 11
  2416. d711 1
  2417. a711 1
  2418.          * buffer, and register change in flow control chars.
  2419. a714 8
  2420.         if (in->sgttyb.sg_flags & RAW) {
  2421.             flow.stop = flow.start = -1;
  2422.         } else {
  2423.             flow.stop = tPtr->tchars.t_stopc;
  2424.             flow.start = tPtr->tchars.t_startc;
  2425.         }
  2426.         (*tPtr->rawProc)(tPtr->rawData, TD_RAW_FLOW_CHARS,
  2427.             sizeof(flow), (char *) &flow, 0, (char *) NULL);
  2428. a817 8
  2429.         if (((tPtr->tchars.t_stopc != in->tchars.t_stopc)
  2430.             || (tPtr->tchars.t_startc != in->tchars.t_startc))
  2431.             && !(tPtr->sgttyb.sg_flags & RAW)) {
  2432.         flow.stop = tPtr->tchars.t_stopc;
  2433.         flow.start = tPtr->tchars.t_startc;
  2434.         (*tPtr->rawProc)(tPtr->rawData, TD_RAW_FLOW_CHARS,
  2435.             sizeof(flow), (char *) &flow, 0, (char *) NULL);
  2436.         }
  2437. d904 29
  2438. d1037 1
  2439. a1037 1
  2440.     int next, sigNum, oldCharsBuffered;
  2441. d1039 1
  2442. d1173 1
  2443. a1173 1
  2444.         sigNum = SIGINT;
  2445. d1175 1
  2446. d1177 2
  2447. a1178 1
  2448.             sizeof(int), (char *) &sigNum, 0, (char *) NULL);
  2449. d1181 1
  2450. d1184 1
  2451. a1184 1
  2452.         sigNum = SIGQUIT;
  2453. d1187 1
  2454. a1187 1
  2455.         sigNum = SIGTSTP;
  2456. d1292 1
  2457. a1292 2
  2458.     int operation;            /* What just happened: TD_BREAK or
  2459.                      * TD_HANGUP. */
  2460. d1294 3
  2461. @
  2462.  
  2463.  
  2464. 1.10
  2465. log
  2466. @Massive upgrade to "new version" that is more modular and
  2467. suitable for inclusion in kernel as well as user processes.
  2468. Plus, there's flow control now and a whole bunch of other
  2469. stuff.
  2470. @
  2471. text
  2472. @d974 1
  2473. a974 1
  2474.     if (tPtr->outCharsBuffered == 0) {
  2475. a1147 1
  2476.         TdFlushInput(tPtr);
  2477. d1150 2
  2478. @
  2479.  
  2480.  
  2481. 1.9
  2482. log
  2483. @Upgrade to use stuff in sys/ioctl.h instead of dev/tty.h.
  2484. @
  2485. text
  2486. @d5 4
  2487. a8 2
  2488.  *    UNIX 4.2 BSD tty driver, using pseudo-devices for the application
  2489.  *    interface and callback procedures for the device interface.
  2490. d10 1
  2491. a10 1
  2492.  * Copyright 1987 Regents of the University of California
  2493. d21 1
  2494. a21 1
  2495. static char rcsid[] = "$Header: /sprite/src/lib/c/etc/RCS/ttyDriver.c,v 1.8 89/01/19 12:36:13 ouster Exp Locker: ouster $ SPRITE (Berkeley)";
  2496. d24 2
  2497. a26 1
  2498. #include <sprite.h>
  2499. a27 2
  2500. #include <dev/pdev.h>
  2501. #include <dev/tty.h>
  2502. d29 1
  2503. a29 2
  2504. #include <list.h>
  2505. #include <status.h>
  2506. a30 2
  2507. #include <string.h>
  2508. #include <sys/file.h>
  2509. d32 1
  2510. a32 1
  2511. #include <td.h>
  2512. d35 1
  2513. a35 1
  2514.  * The string below holds an error message if Td_Open fails.
  2515. a37 25
  2516. char td_ErrorMsg[150];
  2517.  
  2518. /*
  2519.  * The structure below corresponds to an application's stream.  There's
  2520.  * one of these for each open that involves a pseudo-device for which
  2521.  * this module is the server.
  2522.  */
  2523.  
  2524. typedef struct ApplStream {
  2525.     List_Links links;        /* Application streams are linked into a
  2526.                  * list of all streams for the same
  2527.                  * terminal. */
  2528.     struct Terminal *tPtr;    /* Terminal with which this stream is
  2529.                  * associated. */
  2530.     int streamID;        /* Sprite identifier for request stream. */
  2531.     Address requestBuf;        /* A buffer for requests and data from the
  2532.                  * client */
  2533. } ApplStream;
  2534.  
  2535. /*
  2536.  * The structure below corresponds to one terminal (one call to Td_Open).
  2537.  * It maintains our state about the terminal, including stuff like the
  2538.  * input buffer and pointers to each of the open streams on the terminal.
  2539.  */
  2540.  
  2541. a38 7
  2542.     int streamID;        /* Sprite stream identifier for control
  2543.                  * stream for pseudo-device. */
  2544.     List_Links applList;    /* List of all application streams for this
  2545.                  * terminal. */
  2546.     FILE *outputStream;        /* Stream to use for outputting chars. to
  2547.                  * terminal. */
  2548.  
  2549. d41 1
  2550. a41 1
  2551.      * same meanings as in 4.2 BSD;  see the 4.2 BSD terminal driver
  2552. d49 1
  2553. d58 1
  2554. a58 1
  2555.     Proc_PID owner;        /* Identifier of controlling process or process
  2556. d60 2
  2557. d70 5
  2558. a74 5
  2559.     int bufferSize;        /* Number of bytes in inputBuffer. */
  2560.     int lastAdded;        /* Index of last character added to buffer. */
  2561.     int lastRemoved;        /* Index of last place from which character
  2562.                  * was removed from buffer.  If lastAdded =
  2563.                  * lastRemoved, the buffer is empty. */
  2564. d76 2
  2565. a77 2
  2566.                  * etc.) or lastRemoved if none in buffer. */
  2567.     int lastHidden;        /* Value of lastAdded at the time the last
  2568. d87 2
  2569. a88 2
  2570.      * following two variables keep track of an index position in the
  2571.      * buffer, and column just to the right of where that character was
  2572. d90 1
  2573. a90 1
  2574.      * lastHidden or lastRemoved, and has two properties:  a) it will
  2575. d99 35
  2576. a133 2
  2577.     struct Terminal *nextPtr;    /* Next in list of all terminals, or NULL
  2578.                  * for end-of-list. */
  2579. d148 2
  2580. d152 5
  2581. a156 8
  2582. #define EXCLUSIVE 1
  2583. #define BS_IN_PROGRESS 2
  2584. #define LITERAL_NEXT 4
  2585. #define OWNER_FAMILY 8
  2586.  
  2587. Terminal *firstTerminalPtr = NULL;
  2588.                 /* First in list of all terminals being
  2589.                      * being managed right now. */
  2590. d172 3
  2591. d182 1
  2592. a182 1
  2593.     if ((dst) >= size) {        \
  2594. d189 1
  2595. a189 1
  2596.     (dst) = size-1;            \
  2597. d193 26
  2598. a218 78
  2599.  * The structure below describes the format of requests in the write
  2600.  * buffer of an ApplStream.  The kernel queues up requests for us by
  2601.  * appending them to this buffer.  In order to simplify the handling
  2602.  * of requests with a large amount of data, the kernel may break a
  2603.  * (write) request into smaller requests that each fit entirely in
  2604.  * the write buffer.  The MAX_BYTES constant defines this upper limit
  2605.  * on the request data size.  Also remember that writes are asynchronous
  2606.  * so this request buffer size limits the number of writes that can
  2607.  * be done before a context switch to the tty server process is required.
  2608.  */
  2609.  
  2610. #define MAX_BYTES    2048
  2611.  
  2612. typedef struct {
  2613.     Pdev_Request hdr;
  2614.     union {
  2615.     int        i;
  2616.     char        chars[MAX_BYTES];
  2617.     struct sgttyb    sgttyb;
  2618.     struct tchars    tchars;
  2619.     struct ltchars    ltchars;
  2620.     Ioc_Owner    owner;
  2621.     } data;
  2622. } Request;
  2623.  
  2624. /*
  2625.  * WRITE_BUF_SIZE     The size of the buffer containing requests
  2626.  */
  2627.  
  2628. #define REQUEST_BUF_SIZE    sizeof(Request)
  2629.  
  2630. /*
  2631.  * The structure below describes the format of reply messages returned
  2632.  * to the client.
  2633.  */
  2634.  
  2635. typedef struct {
  2636.     Pdev_Reply hdr;
  2637.     union {
  2638.     int        i;
  2639.     char        chars[MAX_BYTES];
  2640.     struct sgttyb    sgttyb;
  2641.     struct tchars    tchars;
  2642.     struct ltchars    ltchars;
  2643.     Ioc_Owner    owner;
  2644.     } data;
  2645. } Reply;
  2646.  
  2647. /*
  2648.  * Forward references to procedures in this file:
  2649.  */
  2650.  
  2651. static void    TdApplRequest();
  2652. static void    TdBackspace();
  2653. static void    TdClose();
  2654. static void    TdControlRequest();
  2655. static void    TdEcho();
  2656. static void    TdFlushInput();
  2657. static void    TdFlushPdev();
  2658. static void    TdIoc();
  2659. static void    TdOpen();
  2660. static void    TdPutChar();
  2661. static void    TdRead();
  2662. static int    TdReady();
  2663. static void    TdReply();
  2664. static void    TdRetypeInput();
  2665. static void    TdSignal();
  2666. static void    TdWrite();
  2667. static int    TdSelectBits();
  2668.  
  2669. /*
  2670.  *----------------------------------------------------------------------
  2671.  *
  2672.  * Td_Open --
  2673.  *
  2674.  *    Arrange for filtering of characters between a pseudo-device
  2675.  *    and a terminal device, emulating the UNIX 4.2 BSD "new"
  2676.  *    terminal driver.
  2677. a219 24
  2678.  * Results:
  2679.  *    The return value is a token for the terminal, which may be
  2680.  *    used in later calls to Td_ procedures.  A NULL return value
  2681.  *    means that the pseudo-device could not be opened.  If realNamePtr
  2682.  *    is non-NULL, *realNamePtr is filled in with a dynamically-
  2683.  *    allocated string giving the actual name of the pseudo-device
  2684.  *    file.
  2685.  *
  2686.  * Side effects:
  2687.  *    A pseudo-device is opened in master mode.  If realNamePtr is
  2688.  *    NULL then name is the complete name of the pseudo device;  if
  2689.  *    realNamePtr is not NULL, then this procedure generates a
  2690.  *    pseudo-device name of the form hostDir/nameXX, where "hostDir"
  2691.  *    is the name of a standard host-specific directory for holding
  2692.  *    terminal pseudo-devices and XX is an integer id appended to
  2693.  *    "name" in order to find a device that isn't already in use.
  2694.  *    Once this procedure returns, this module manages the pseudo
  2695.  *    device to emulate the characteristics of a 4.2BSD terminal.
  2696.  *    During calls to other procedures in this module,  data will get
  2697.  *    added to outputStream.  Callbacks are set up using the Fs_Dispatch
  2698.  *    facilities, so that this module gets notified when the pdev
  2699.  *    channels have data ready.  The caller must use the Fs_Dispatch
  2700.  *    facilities.
  2701.  *
  2702. d224 13
  2703. a236 12
  2704. Td_Open(name, outputStream, realNamePtr)
  2705.     char *name;            /* Name of pseudo-device file to use for
  2706.                  * application interface, or key for generating
  2707.                  * name (if realNamePtr != NULL).  If no
  2708.                  * pseudo-device by that name exists, one
  2709.                  * will be created. */
  2710.     FILE *outputStream;        /* Where to write characters destined for
  2711.                  * the device. */
  2712.     char **realNamePtr;        /* If not NULL, then use "name" as a key for
  2713.                  * a name (see above) and store actual name of
  2714.                  * pseudo-device here.  The memory for the
  2715.                  * string is dynamically allocated. */
  2716. a237 1
  2717.     int streamID;
  2718. a238 59
  2719.     int pdevOpenFlags;
  2720.  
  2721.     /*
  2722.      * Pick a file name to use for the pseudo-device, if the caller didn't
  2723.      * give us one, then open the pseudo-device as the controlling process.
  2724.      */
  2725.  
  2726.     pdevOpenFlags = O_MASTER|O_RDWR|O_CREAT;
  2727.     if (realNamePtr != NULL) {
  2728.     char hostName[50];
  2729.     int i;
  2730.     char *actualName;
  2731.  
  2732.     if (gethostname(hostName, 20) != 0) {
  2733.         sprintf(td_ErrorMsg, "couldn't get host name (%s)",
  2734.             strerror(errno));
  2735.         return (Td_Terminal) NULL;
  2736.     } else {
  2737.         /*
  2738.          * Trim off domain name, if any
  2739.          */
  2740.         char *cp;
  2741.  
  2742.         cp = index(hostName, '.');
  2743.         if (cp != (char *)NULL) {
  2744.         *cp = '\0';
  2745.         }
  2746.     }
  2747.     actualName = (char *) malloc((unsigned) (12 + strlen(hostName)
  2748.         + strlen(name)));
  2749.     for (i = 1; i < 20; i++) {
  2750.         sprintf(actualName, "/hosts/%s/%s%d", hostName,
  2751.             name, i);
  2752.  
  2753.         /*
  2754.          * Because of umask, the file's mode may not actually get set
  2755.          * to 0666.  Once the file is open, change the mode explicitly
  2756.          * to force it.
  2757.          */
  2758.  
  2759.         streamID = open(actualName, pdevOpenFlags, 0666);
  2760.         if (streamID >= 0) {
  2761.         fchmod(streamID, 0666);
  2762.         *realNamePtr = actualName;
  2763.         goto gotStream;
  2764.         }
  2765.     }
  2766.     free((char *) actualName);
  2767.     sprintf(td_ErrorMsg, 
  2768.         "couldn't open a pseudo-device in \"/hosts/%s\"", hostName);
  2769.     return (Td_Terminal) NULL;
  2770.     } else {
  2771.     streamID = open(name, pdevOpenFlags, 0666);
  2772.     if (streamID < 0) {
  2773.         sprintf(td_ErrorMsg, "couldn't open \"%s\" (%s)",
  2774.             name, strerror(errno));
  2775.         return (Td_Terminal) NULL;
  2776.     }
  2777.     }
  2778. a239 1
  2779.     gotStream:
  2780. a240 8
  2781.     tPtr->streamID = streamID;
  2782.     List_Init(&tPtr->applList);
  2783.     tPtr->outputStream = outputStream;
  2784.  
  2785.     /*
  2786.      * Should set (or get?) device's baud rate here.
  2787.      */
  2788.  
  2789. d245 1
  2790. d250 3
  2791. a252 3
  2792.     tPtr->bufferSize = 100;
  2793.     tPtr->lastAdded = 0;
  2794.     tPtr->lastRemoved = 0;
  2795. d257 10
  2796. a266 2
  2797.     tPtr->nextPtr = firstTerminalPtr;
  2798.     firstTerminalPtr = tPtr;
  2799. a267 3
  2800.     Fs_EventHandlerCreate(streamID, FS_READABLE, TdControlRequest,
  2801.         (ClientData) tPtr);
  2802.  
  2803. d274 1
  2804. a274 1
  2805.  * Td_Close --
  2806. d276 2
  2807. a277 2
  2808.  *    Close down a terminal pseudo-device and release all of the
  2809.  *    state associated with it.
  2810. d283 3
  2811. a285 3
  2812.  *    Memory gets recycled, and clients on the other end of the
  2813.  *    pseudo-device will probably terminate.  After this call,
  2814.  *    the caller should never again use terminal.
  2815. d291 3
  2816. a293 3
  2817. Td_Close(terminal)
  2818.     Td_Terminal terminal;    /* Token identifying the terminal (the return
  2819.                  * value from a previous Td_Open call). */
  2820. d296 1
  2821. a296 8
  2822.     register Terminal *tPtr2;
  2823.     register ApplStream *applPtr;
  2824.  
  2825.     while (!List_IsEmpty(&tPtr->applList)) {
  2826.     applPtr = (ApplStream *) List_First(&tPtr->applList);
  2827.     TdClose(tPtr, applPtr, FALSE);
  2828.     }
  2829.     close(tPtr->streamID);
  2830. d298 1
  2831. a298 10
  2832.     close(tPtr->streamID);
  2833.     if (firstTerminalPtr == tPtr) {
  2834.     firstTerminalPtr = tPtr->nextPtr;
  2835.     } else {
  2836.     for (tPtr2 = firstTerminalPtr; tPtr2->nextPtr != tPtr;
  2837.         tPtr2 = tPtr2->nextPtr) {
  2838.         /* Empty loop body. */
  2839.     }
  2840.     tPtr2->nextPtr = tPtr->nextPtr;
  2841.     }
  2842. d305 5
  2843. a309 1
  2844.  * Td_InputChar --
  2845. d311 20
  2846. a330 34
  2847.  *    When one or more characters arrive from the "device" end of
  2848.  *    a tty connection, the client calls this routine to pass in
  2849.  *    the characters, one at a time.  Td_InputChar handles echoing
  2850.  *    and line editing, as appropriate, and .
  2851.  *
  2852.  * Results:
  2853.  *    None.
  2854.  *
  2855.  * Side effects:
  2856.  *    Characters may get output to the device, or passed on to
  2857.  *    the application.
  2858.  *
  2859.  *----------------------------------------------------------------------
  2860.  */
  2861.  
  2862. void
  2863. Td_InputChar(terminal, c)
  2864.     Td_Terminal terminal;    /* Token identifying the terminal from
  2865.                  * which the characters came (the return
  2866.                  * value from a previous Td_Open call). */
  2867.     register char c;        /* Character to be input. */
  2868. {
  2869.     register Terminal *tPtr = (Terminal *) terminal;
  2870.     int next;
  2871.  
  2872.     /*
  2873.      * See if we're supposed to re-echo all the characters in the
  2874.      * input buffer.
  2875.      */
  2876.     
  2877.     if (tPtr->localMode & LPENDIN) {
  2878.     tPtr->localMode &= ~LPENDIN;
  2879.     TdRetypeInput(tPtr, tPtr->lastBreak);
  2880.     }
  2881. d332 2
  2882. a333 156
  2883.     /*
  2884.      * Handle raw mode and literal characters specially.
  2885.      */
  2886.     
  2887.     if (tPtr->sgttyb.sg_flags & RAW) {
  2888.     goto addToBuffer;
  2889.     }
  2890.     if (tPtr->flags & LITERAL_NEXT) {
  2891.     tPtr->flags &= ~LITERAL_NEXT;
  2892.     goto addToBuffer;
  2893.     }
  2894.  
  2895.     /*
  2896.      * Handle line-editing characters such as erase and kill.
  2897.      */
  2898.     
  2899.     c &= 0177;
  2900.     if ((c == '\r') && (tPtr->sgttyb.sg_flags & CRMOD)) {
  2901.     c = '\n';
  2902.     }
  2903.     if (!(tPtr->sgttyb.sg_flags & CBREAK)) {
  2904.     if (c == tPtr->sgttyb.sg_erase) {        /* Backspace. */
  2905.         if (tPtr->lastAdded != tPtr->lastBreak) {
  2906.         TdBackspace(tPtr);
  2907.         }
  2908.         return;
  2909.     } else if (c == tPtr->ltchars.t_werasc)    {    /* Delete word. */
  2910.         Boolean gotNonSpace = FALSE;
  2911.  
  2912.         while (tPtr->lastAdded != tPtr->lastBreak) {
  2913.         if (isspace(tPtr->inputBuffer[tPtr->lastAdded])) {
  2914.             if (gotNonSpace) {
  2915.             break;
  2916.             }
  2917.         } else {
  2918.             gotNonSpace = TRUE;
  2919.         }
  2920.         TdBackspace(tPtr);
  2921.         }
  2922.         return;
  2923.     } else if (c == tPtr->sgttyb.sg_kill) {        /* Delete line. */
  2924.         if ((tPtr->lastHidden != -1) || !(tPtr->localMode & LCRTKIL)) {
  2925.         TdEcho(tPtr, c);
  2926.         TdEcho(tPtr, '\n');
  2927.         tPtr->lastAdded = tPtr->lastBreak;
  2928.         tPtr->lastHidden = -1;
  2929.         } else {
  2930.         while (tPtr->lastAdded != tPtr->lastBreak) {
  2931.             TdBackspace(tPtr);
  2932.         }
  2933.         }
  2934.         return;
  2935.     } else if (c == tPtr->ltchars.t_rprntc) {    /* Re-echo all. */
  2936.         TdEcho(tPtr, c);
  2937.         TdEcho(tPtr, '\n');
  2938.         TdRetypeInput(tPtr, tPtr->lastRemoved);
  2939.         return;
  2940.     }
  2941.     }
  2942.  
  2943.     if (c == tPtr->ltchars.t_lnextc) {
  2944.     tPtr->flags |= LITERAL_NEXT;
  2945.     return;
  2946.     }
  2947.  
  2948.     /*
  2949.      * Generate signals in response to certain input characters.  If this
  2950.      * isn't a signal character, then officially add it to the input
  2951.      * buffer.
  2952.      */
  2953.  
  2954.     if (c == tPtr->tchars.t_intrc) {
  2955.     TdSignal(tPtr, SIG_INTERRUPT);
  2956.     goto echo;
  2957.     } else if (c == tPtr->tchars.t_quitc) {
  2958.     TdSignal(tPtr, SIG_SUSPEND);
  2959.     goto echo;
  2960.     } else if (c == tPtr->ltchars.t_suspc) {
  2961.     TdSignal(tPtr, SIG_TTY_SUSPEND);
  2962.     goto echo;
  2963.     }
  2964.  
  2965.     /*
  2966.      * If the buffer is full, then reallocate it with a size twice as
  2967.      * large.  Then add the character to the buffer.
  2968.      */
  2969.  
  2970.     addToBuffer:
  2971.     NEXT(tPtr->lastAdded, tPtr->bufferSize, next);
  2972.     if (next == tPtr->lastRemoved) {
  2973.     char *newBuffer;
  2974.     int src, dst;
  2975.  
  2976.     newBuffer = malloc((unsigned) 2*tPtr->bufferSize);
  2977.     for (src = tPtr->lastRemoved, dst = 0; src != tPtr->lastAdded; ) {
  2978.         NEXT(src, tPtr->bufferSize, src);
  2979.         dst += 1;
  2980.         newBuffer[dst] = tPtr->inputBuffer[src];
  2981.     }
  2982.     tPtr->lastBreak -= tPtr->lastRemoved;
  2983.     if (tPtr->lastBreak < 0) {
  2984.         tPtr->lastBreak += tPtr->bufferSize;
  2985.     }
  2986.     if (tPtr->lastHidden != -1) {
  2987.         tPtr->lastHidden -= tPtr->lastRemoved;
  2988.         if (tPtr->lastHidden < 0) {
  2989.         tPtr->lastHidden += tPtr->bufferSize;
  2990.         }
  2991.     }
  2992.     tPtr->inputBuffer = newBuffer;
  2993.     tPtr->bufferSize *= 2;
  2994.     tPtr->lastRemoved = 0;
  2995.     tPtr->lastAdded = dst;
  2996.     NEXT(dst, tPtr->bufferSize, next);
  2997.     }
  2998.     tPtr->inputBuffer[next] = c;
  2999.     tPtr->lastAdded = next;
  3000.  
  3001.     /*
  3002.      * Echo.
  3003.      */
  3004.  
  3005.     echo:
  3006.     if ((tPtr->sgttyb.sg_flags & ECHO) && !(tPtr->sgttyb.sg_flags & RAW)) {
  3007.     if (tPtr->flags & BS_IN_PROGRESS) {
  3008.         TdPutChar(tPtr, '/');
  3009.         tPtr->flags &= ~BS_IN_PROGRESS;
  3010.     }
  3011.     TdEcho(tPtr, c);
  3012.     }
  3013.  
  3014.     /*
  3015.      * Are there any characters that are ready for reading?  If so,
  3016.      * set the kernel's select state to be readable.
  3017.      */
  3018.  
  3019.     if ((tPtr->sgttyb.sg_flags & (RAW|CBREAK)) || (c == tPtr->tchars.t_eofc) ||
  3020.         (c == tPtr->tchars.t_brkc) || (c == '\n')) {
  3021.     register ApplStream *applPtr;
  3022.     ReturnStatus status;
  3023.     int selectBits;
  3024.  
  3025.     tPtr->lastBreak = tPtr->lastAdded;
  3026.     tPtr->lastHidden = -1;
  3027.     tPtr->keyIndex = tPtr->lastAdded;
  3028.     tPtr->keyColumn = tPtr->column;
  3029.     selectBits = TdSelectBits(tPtr);
  3030.     LIST_FORALL(&tPtr->applList, (List_Links *) applPtr) {
  3031.         status = Fs_IOControl(applPtr->streamID, IOC_PDEV_READY,
  3032.             sizeof(int), (Address) &selectBits, 0,
  3033.             (Address) NULL);
  3034.         if (status != SUCCESS) {
  3035.         panic("Td_InputChar set select state: %s",
  3036.             Stat_GetMsg(status));
  3037.         }
  3038.     }
  3039. d335 10
  3040. d350 1
  3041. a350 1
  3042.  * Td_GetState --
  3043. d352 2
  3044. a353 1
  3045.  *    Return all of the state associated with the terminal.
  3046. d356 1
  3047. a356 2
  3048.  *    The areas pointed to by the arguments get filled in with
  3049.  *    the corresponding pieces of the terminal's state.
  3050. d359 1
  3051. a359 1
  3052.  *    None.
  3053. d365 3
  3054. a367 6
  3055. Td_GetState(terminal, basicPtr, charsPtr, localCharsPtr, localModePtr)
  3056.     Td_Terminal terminal;        /* Token for terminal. */
  3057.     struct sgttyb *basicPtr;        /* Where to store sgttyb stuff. */
  3058.     struct tchars *charsPtr;        /* Where to store tchars stuff. */
  3059.     struct ltchars *localCharsPtr;    /* Where to store ltchars stuff. */
  3060.     int *localModePtr;            /* Where to store local mode word. */
  3061. d370 5
  3062. a374 4
  3063.     *basicPtr = tPtr->sgttyb;
  3064.     *charsPtr = tPtr->tchars;
  3065.     *localCharsPtr = tPtr->ltchars;
  3066.     *localModePtr = tPtr->localMode;
  3067. d380 1
  3068. a380 1
  3069.  * Td_SetState --
  3070. d382 2
  3071. a383 1
  3072.  *    Change the internal state associated with a terminal.
  3073. d385 39
  3074. a423 9
  3075.  * Results:
  3076.  *    None.
  3077.  *
  3078.  * Side effects:
  3079.  *    The terminal's state gets set from the parameters.  The
  3080.  *    terminal's input buffer may also get flushed.
  3081.  *
  3082.  *----------------------------------------------------------------------
  3083.  */
  3084. d425 4
  3085. a428 142
  3086. void
  3087. Td_SetState(terminal, basicPtr, charsPtr, localCharsPtr, localMode, flush)
  3088.     Td_Terminal terminal;        /* Token for terminal. */
  3089.     struct sgttyb *basicPtr;        /* New sgttyb stuff. */
  3090.     struct tchars *charsPtr;        /* New tchars. */
  3091.     struct ltchars *localCharsPtr;    /* New ltchars. */
  3092.     int localMode;            /* New local mode word. */
  3093.     Boolean flush;            /* If TRUE, then flush input buffer. */
  3094. {
  3095.     register Terminal *tPtr = (Terminal *) terminal;
  3096.  
  3097.     tPtr->sgttyb = *basicPtr;
  3098.     tPtr->tchars = *charsPtr;
  3099.     tPtr->ltchars = *localCharsPtr;
  3100.     tPtr->localMode = localMode;
  3101.     if (flush) {
  3102.     TdFlushInput(tPtr);
  3103.     }
  3104. }
  3105.  
  3106. /*
  3107.  *----------------------------------------------------------------------
  3108.  *
  3109.  * TdControlRequest --
  3110.  *
  3111.  *    This procedure is invoked by Fs_Dispatcher when the control
  3112.  *    stream for a pseudo-device is readable.  This means that
  3113.  *    a new stream is being opened on the pdev;  TdControlRequest
  3114.  *    handles this.
  3115.  *
  3116.  * Results:
  3117.  *    None.
  3118.  *
  3119.  * Side effects:
  3120.  *    Add a new application stream to the pdev.
  3121.  *
  3122.  *----------------------------------------------------------------------
  3123.  */
  3124.  
  3125. void
  3126. TdControlRequest(tPtr)
  3127.     register Terminal *tPtr;    /* Terminal whose control stream is ready. */
  3128. {
  3129.     Pdev_Notify notify;
  3130.     register ApplStream *applPtr;
  3131.     int numBytes;
  3132.     Pdev_SetBufArgs setBuf;
  3133.     int true = 1;
  3134.  
  3135.     /*
  3136.      * Read the control stream for a message containing a new streamID.
  3137.      */
  3138.  
  3139.     numBytes = read(tPtr->streamID, (char *) ¬ify, sizeof(notify));
  3140.     if (numBytes != sizeof(notify)) {
  3141.     panic("%s; status \"%s\", count %d",
  3142.         "Td_Check couldn't read control stream",
  3143.         strerror(errno), numBytes);
  3144.     }
  3145.     if (notify.magic != PDEV_NOTIFY_MAGIC) {
  3146.     panic("%s: %d", "Td_Check got bad notify magic number",
  3147.         notify.magic);
  3148.     }
  3149.  
  3150.     /*
  3151.      * Set up the application state.  This includes a request buffer used
  3152.      * by the kernel to pass client requests to us.
  3153.      */
  3154.  
  3155.     applPtr = (ApplStream *) malloc(sizeof(ApplStream));
  3156.     List_InitElement(&applPtr->links);
  3157.     List_Insert(&applPtr->links, LIST_ATFRONT(&tPtr->applList));
  3158.     applPtr->streamID = notify.newStreamID;
  3159.     applPtr->tPtr = tPtr;
  3160.     applPtr->requestBuf = (Address) malloc(REQUEST_BUF_SIZE);
  3161.     setBuf.requestBufAddr = applPtr->requestBuf;
  3162.     setBuf.requestBufSize = REQUEST_BUF_SIZE;
  3163.     setBuf.readBufAddr = NULL;
  3164.     setBuf.readBufSize = 0;
  3165.     Fs_IOControl(applPtr->streamID, IOC_PDEV_WRITE_BEHIND,
  3166.             sizeof(int), (Address)&true, 0, (Address) NULL);
  3167.     Fs_IOControl(applPtr->streamID, IOC_PDEV_SET_BUF,
  3168.             sizeof(Pdev_SetBufArgs), (Address)&setBuf,
  3169.             0, (Address) NULL);
  3170.     Fs_EventHandlerCreate(notify.newStreamID, FS_READABLE, TdApplRequest,
  3171.         (ClientData) applPtr);
  3172. }
  3173.  
  3174. /*
  3175.  *----------------------------------------------------------------------
  3176.  *
  3177.  * TdApplRequest --
  3178.  *
  3179.  *    This procedure is invoked by Fs_Dispatch when a request appears
  3180.  *    for an application stream.   This procedure reads the request and
  3181.  *    dispatches to a routine to handle the request.
  3182.  *
  3183.  * Results:
  3184.  *    None.
  3185.  *
  3186.  * Side effects:
  3187.  *    Characters may be output to devices or returned from a device's
  3188.  *    internal buffer to an application.
  3189.  *
  3190.  *----------------------------------------------------------------------
  3191.  */
  3192.  
  3193. void
  3194. TdApplRequest(applPtr)
  3195.     register ApplStream *applPtr;    /* Application stream that has a
  3196.                      * request ready for processing. */
  3197. {
  3198.     register Terminal *tPtr = applPtr->tPtr;
  3199.     Pdev_BufPtrs bufPtrs;
  3200.     Request *requestPtr;
  3201.     int numBytes;
  3202.  
  3203.     /*
  3204.      * Read the current pointers for the request buffer.
  3205.      */
  3206.  
  3207.     numBytes = read(applPtr->streamID, (char *) &bufPtrs,
  3208.         sizeof(Pdev_BufPtrs));
  3209.     if (numBytes != sizeof(Pdev_BufPtrs)) {
  3210.     panic("%s; status \"%s\", count %d",
  3211.         "Td_Check had trouble reading request buffer pointers",
  3212.         strerror(errno), numBytes);
  3213.     }
  3214.     if (bufPtrs.magic != PDEV_BUF_PTR_MAGIC) {
  3215.     panic("%s: %d", "Td_Check got bad pointer magic number",
  3216.         bufPtrs.magic);
  3217.     }
  3218.     /*
  3219.      * While there are still requests in the buffer, service them.
  3220.      */
  3221.     while (bufPtrs.requestFirstByte < bufPtrs.requestLastByte) {
  3222.     requestPtr =
  3223.         (Request *)&applPtr->requestBuf[bufPtrs.requestFirstByte];
  3224.     if (requestPtr->hdr.hdr.magic != PDEV_REQUEST_MAGIC) {
  3225.         panic("TdApplRequest, bad request magic # 0x%x\n",
  3226.                 requestPtr->hdr.hdr.magic);
  3227.     }
  3228. d430 7
  3229. a436 20
  3230.     switch (requestPtr->hdr.hdr.operation) {
  3231.         case PDEV_OPEN:
  3232.         TdOpen(tPtr, applPtr, requestPtr);
  3233.         break;
  3234.         case PDEV_CLOSE:
  3235.         TdClose(tPtr, applPtr, TRUE);
  3236.         break;
  3237.         case PDEV_READ:
  3238.         TdRead(tPtr, applPtr, requestPtr);
  3239.         break;
  3240.         case PDEV_WRITE:
  3241.         case PDEV_WRITE_ASYNC:
  3242.         TdWrite(tPtr, applPtr, requestPtr);
  3243.         break;
  3244.         case PDEV_IOCTL:
  3245.         TdIoc(tPtr, applPtr, requestPtr);
  3246.         break;
  3247.         default:
  3248.         panic("Td_Check: bad request on request stream: %d",
  3249.             requestPtr->hdr.hdr.operation);
  3250. d438 2
  3251. a439 128
  3252.     /*
  3253.      * Tell the kernel we removed a request and see if there are any more.
  3254.      */
  3255.     bufPtrs.requestFirstByte += requestPtr->hdr.hdr.messageSize;
  3256.     Fs_IOControl(applPtr->streamID, IOC_PDEV_SET_PTRS,
  3257.             sizeof(Pdev_BufPtrs), (Address)&bufPtrs,
  3258.             0, (Address) NULL);
  3259.     }
  3260. }
  3261.  
  3262. /*
  3263.  *----------------------------------------------------------------------
  3264.  *
  3265.  * TdOpen --
  3266.  *
  3267.  *    This procedure is called when an PDEV_OPEN request is
  3268.  *    received over an application stream.
  3269.  *
  3270.  * Results:
  3271.  *    None.
  3272.  *
  3273.  * Side effects:
  3274.  *    If the terminal is in exclusive mode then reject the open
  3275.  *    and close down the application's stream.  Otherwise, accept
  3276.  *    it.
  3277.  *
  3278.  *----------------------------------------------------------------------
  3279.  */
  3280.  
  3281. static void
  3282. TdOpen(tPtr, applPtr, reqPtr)
  3283.     Terminal *tPtr;        /* Terminal for which a new stream was just
  3284.                  * opened. */
  3285.     ApplStream *applPtr;    /* Application's stream. */
  3286.     Request *reqPtr;        /* Information about the open request. */
  3287. {
  3288.     if (reqPtr->hdr.hdr.requestSize != 0) {
  3289.     panic("TdOpen got %d bytes of data with open or dup request",
  3290.         reqPtr->hdr.hdr.requestSize);
  3291.     }
  3292.     if (tPtr->flags & EXCLUSIVE) {
  3293.     TdReply(applPtr, (ReturnStatus) FS_FILE_BUSY, 0);
  3294.     TdClose(tPtr, applPtr, FALSE);
  3295.     } else {
  3296.     TdReply(applPtr, (ReturnStatus) SUCCESS, TdSelectBits(tPtr));
  3297.     }
  3298. }
  3299.  
  3300. /*
  3301.  *----------------------------------------------------------------------
  3302.  *
  3303.  * TdClose --
  3304.  *
  3305.  *    This procedure is called to recycle all the information
  3306.  *    associated with an application's stream.
  3307.  *
  3308.  * Results:
  3309.  *    None.
  3310.  *
  3311.  * Side effects:
  3312.  *    The request stream gets closed, and our information about
  3313.  *    the application stream gets freed up.
  3314.  *
  3315.  *----------------------------------------------------------------------
  3316.  */
  3317.  
  3318. static void
  3319. TdClose(tPtr, applPtr, sendReply)
  3320.     register Terminal *tPtr;        /* Terminal for which request was
  3321.                      * received. */
  3322.     register ApplStream *applPtr;    /* Application stream info. */
  3323.     Boolean sendReply;            /* TRUE if we should reply to the
  3324.                      * close request.  This is done in
  3325.                      * normal termination.  FALSE means
  3326.                      * no reply needed, used in error
  3327.                      * recovery */
  3328. {
  3329.     if (sendReply) {
  3330.     TdReply(applPtr, (ReturnStatus) SUCCESS, 0);
  3331.     }
  3332.     List_Remove(&applPtr->links);
  3333.     Fs_EventHandlerDestroy(applPtr->streamID);
  3334.     close(applPtr->streamID);
  3335.     free((char *) applPtr->requestBuf);
  3336.     free((char *) applPtr);
  3337.  
  3338.     if (List_IsEmpty(&tPtr->applList)) {
  3339.     tPtr->flags &= ~EXCLUSIVE;
  3340.     }
  3341. }
  3342.  
  3343. /*
  3344.  *----------------------------------------------------------------------
  3345.  *
  3346.  * TdRead --
  3347.  *
  3348.  *    This procedure is called when an PDEV_READ request is
  3349.  *    received over a request stream.  Read ahead is not implemented
  3350.  *    because we want to see each request so we can enforce ownership
  3351.  *    so we see every client read request.  Only the controlling
  3352.  *    process (set via the IOC_OWNER IOControl) is allowed to read.
  3353.  *    Other processes get signaled with SIG_TTY_INPUT.
  3354.  *
  3355.  * Results:
  3356.  *    None.
  3357.  *
  3358.  * Side effects:
  3359.  *    Updates the lastRemoved and lastHidden pointers into the terminal's
  3360.  *    input buffer.  The available data is moved to the pseudo-device
  3361.  *    read buffer and the kernel is poked.
  3362.  *
  3363.  *----------------------------------------------------------------------
  3364.  */
  3365.  
  3366. static void
  3367. TdRead(tPtr, applPtr, reqPtr)
  3368.     register Terminal *tPtr;    /* Terminal for which request was received. */
  3369.     ApplStream *applPtr;    /* Application stream info. */
  3370.     Request *reqPtr;        /* Information about the request. */
  3371. {
  3372.     Reply reply;
  3373.     register Reply *replyPtr;
  3374.     int src, count;
  3375.     ReturnStatus status;
  3376.  
  3377.     if (reqPtr->hdr.hdr.requestSize != 0) {
  3378.     panic("TdRead got %d requestSize for read operation",
  3379.         reqPtr->hdr.hdr.requestSize);
  3380. d447 3
  3381. d451 5
  3382. a455 14
  3383.     TdRetypeInput(tPtr, tPtr->lastBreak);
  3384.     }
  3385.  
  3386.     /*
  3387.      * See if this application is in the right process group.  If not,
  3388.      * then signal it and don't give it any input.
  3389.      */
  3390.  
  3391.     if (tPtr->flags & OWNER_FAMILY) {
  3392.     if (reqPtr->hdr.param.read.familyID != tPtr->owner) {
  3393.         notOwner:
  3394.         Sig_Send(SIG_TTY_INPUT, reqPtr->hdr.param.read.procID, FALSE);
  3395.         TdReply(applPtr, (ReturnStatus) FS_WOULD_BLOCK, FS_WRITABLE);
  3396.         return;
  3397. a456 2
  3398.     } else if (reqPtr->hdr.param.read.procID != tPtr->owner) {
  3399.     goto notOwner;
  3400. d464 4
  3401. a467 3
  3402.     if (tPtr->lastBreak == tPtr->lastRemoved) {
  3403.     TdReply(applPtr, (ReturnStatus) FS_WOULD_BLOCK, FS_WRITABLE);
  3404.     return;
  3405. d469 17
  3406. a485 13
  3407.  
  3408.     /*
  3409.      * Count how many bytes should be returned to the user, and
  3410.      * update the terminal's input buffer pointer.
  3411.      */
  3412.     reply.hdr.replySize = 0;
  3413.     src = tPtr->lastRemoved;
  3414.     while (tPtr->lastRemoved != tPtr->lastBreak) {
  3415.     NEXT(tPtr->lastRemoved, tPtr->bufferSize, tPtr->lastRemoved);
  3416.     if (tPtr->lastRemoved == tPtr->lastHidden) {
  3417.         tPtr->lastHidden = -1;
  3418.     }
  3419.     reply.hdr.replySize++;
  3420. a486 1
  3421.         register char c = tPtr->inputBuffer[tPtr->lastRemoved];
  3422. d488 1
  3423. a488 1
  3424.         reply.hdr.replySize--;    /* Don't return end-of-file chars. */
  3425. a493 3
  3426.     if (reply.hdr.replySize >= reqPtr->hdr.hdr.replySize) {
  3427.         break;
  3428.     }
  3429. d495 2
  3430. d498 3
  3431. a500 7
  3432.     if (reply.hdr.replySize > MAX_BYTES) {
  3433.     /*
  3434.      * Have to dynamically allocate a large enough reply.
  3435.      */
  3436.     replyPtr = (Reply *) malloc((unsigned) (sizeof(Pdev_Reply)
  3437.         + reply.hdr.replySize));
  3438.     replyPtr->hdr = reply.hdr;
  3439. d502 1
  3440. a502 1
  3441.     replyPtr = &reply;
  3442. d504 21
  3443. a524 36
  3444.  
  3445.     /*
  3446.      * Copy the data into the reply and give it to the kernel.
  3447.      */
  3448.  
  3449.     replyPtr->hdr.magic = PDEV_REPLY_MAGIC;
  3450.     replyPtr->hdr.status = SUCCESS;
  3451.     replyPtr->hdr.selectBits = TdSelectBits(tPtr);
  3452.     for (count = 0 ; count < reply.hdr.replySize ; count++) {
  3453.     NEXT(src, tPtr->bufferSize, src);
  3454.     replyPtr->data.chars[count] = tPtr->inputBuffer[src];
  3455.     }
  3456.     replyPtr->hdr.replyBuf = &replyPtr->data.chars[0];
  3457.     status = Fs_IOControl(applPtr->streamID, IOC_PDEV_REPLY,
  3458.                 sizeof(Pdev_Reply),
  3459.                 (Address) replyPtr, 0, (Address) NULL);
  3460.     if (status != SUCCESS) {
  3461.     panic("%s; status \"%s\"", "Td_Read couldn't send reply",
  3462.         Stat_GetMsg(status));
  3463.     }
  3464. }
  3465.  
  3466. /*
  3467.  *----------------------------------------------------------------------
  3468.  *
  3469.  * TdWrite --
  3470.  *
  3471.  *    This procedure is called when an PDEV_WRITE request is
  3472.  *    received over a request stream.
  3473.  *
  3474.  * Results:
  3475.  *    None.
  3476.  *
  3477.  * Side effects:
  3478.  *    Perform output processing on the characters, if enabled, and
  3479.  *    pass the characters on to the device.
  3480. d530 14
  3481. a543 6
  3482. static void
  3483. TdWrite(tPtr, applPtr, reqPtr)
  3484.     Terminal *tPtr;            /* Terminal for which request was
  3485.                      * received. */
  3486.     ApplStream *applPtr;        /* Application stream info. */
  3487.     register Request *reqPtr;        /* Information about the request. */
  3488. d545 1
  3489. a545 1
  3490.     register char *p;
  3491. d547 1
  3492. d549 1
  3493. a549 5
  3494.     /*
  3495.      * Handle the write request in a loop, processing all the characters
  3496.      * in the request data buffer, then refilling the buffer, until there
  3497.      * are no more characters left.
  3498.      */
  3499. d551 3
  3500. a553 3
  3501.     for (p = reqPtr->data.chars; reqPtr->hdr.hdr.requestSize > 0;
  3502.      p++, reqPtr->hdr.hdr.requestSize--) {
  3503.     c = *p;
  3504. d555 1
  3505. a555 1
  3506.         putc(c, tPtr->outputStream);
  3507. d568 1
  3508. a568 1
  3509.  
  3510. d570 12
  3511. a581 3
  3512.     tPtr->keyIndex = tPtr->lastAdded;
  3513.     if (tPtr->lastAdded != tPtr->lastRemoved) {
  3514.     tPtr->lastHidden = tPtr->lastAdded;
  3515. d583 60
  3516. d644 10
  3517. a653 33
  3518.     /*
  3519.      * Don't need to reply explicitly because the write has already
  3520.      * been handled for the client by the kernel.
  3521.      */
  3522. }
  3523.  
  3524. /*
  3525.  *----------------------------------------------------------------------
  3526.  *
  3527.  * TdIoc --
  3528.  *
  3529.  *    This procedure is called when an PDEV_IOCONTROL request is
  3530.  *    received over a request stream.
  3531.  *
  3532.  * Results:
  3533.  *    None.
  3534.  *
  3535.  * Side effects
  3536.  *    Read the IOControl input data, if any, process the request,
  3537.  *    and send a response back.  The exact actions taken depend on
  3538.  *    the IOControl operation.
  3539.  *
  3540.  *----------------------------------------------------------------------
  3541.  */
  3542.  
  3543. static void
  3544. TdIoc(tPtr, applPtr, reqPtr)
  3545.     register Terminal *tPtr;    /* Terminal for which request was received. */
  3546.     ApplStream *applPtr;    /* Application stream info. */
  3547.     Request *reqPtr;        /* Information about the request. */
  3548. {
  3549.     Reply reply;
  3550.     ReturnStatus status;
  3551. d655 3
  3552. a657 2
  3553.     reply.hdr.replySize = 0;
  3554.     switch (reqPtr->hdr.param.ioctl.command) {
  3555. d660 2
  3556. a661 2
  3557.         if ((reqPtr->hdr.hdr.requestSize != sizeof(int))
  3558.             || (reqPtr->data.i != NTTYDISC)) {
  3559. d667 1
  3560. a667 1
  3561.         if (reqPtr->hdr.hdr.requestSize != 0) {
  3562. d670 3
  3563. a672 2
  3564.         reply.data.i = NTTYDISC;
  3565.         reply.hdr.replySize = sizeof(int);
  3566. d676 1
  3567. a676 1
  3568.         if (reqPtr->hdr.hdr.requestSize != 0) {
  3569. d679 2
  3570. a680 2
  3571.         reply.data.sgttyb = tPtr->sgttyb;
  3572.         reply.hdr.replySize = sizeof(struct sgttyb);
  3573. d684 6
  3574. d692 1
  3575. a692 1
  3576.         if (reqPtr->hdr.hdr.requestSize != sizeof(struct sgttyb)) {
  3577. d695 6
  3578. a700 1
  3579.         if ((tPtr->sgttyb.sg_flags ^ reqPtr->data.sgttyb.sg_flags) & RAW) {
  3580. d702 8
  3581. d711 1
  3582. a711 1
  3583.         tPtr->sgttyb = reqPtr->data.sgttyb;
  3584. d715 1
  3585. a715 1
  3586.         if (reqPtr->hdr.hdr.requestSize != 0) {
  3587. d722 1
  3588. a722 1
  3589.         if (reqPtr->hdr.hdr.requestSize != 0) {
  3590. d732 1
  3591. a732 1
  3592.         if (reqPtr->hdr.hdr.requestSize != 0) {
  3593. d736 1
  3594. d740 1
  3595. a740 1
  3596.         if (reqPtr->hdr.hdr.requestSize != 1) {
  3597. d743 1
  3598. a743 1
  3599.         Td_InputChar((Td_Terminal) tPtr, reqPtr->data.chars[0]);
  3600. d745 20
  3601. a764 6
  3602.  
  3603.     case IOC_TTY_SET_BREAK:            /* Not implemented. */
  3604.         goto invalid;
  3605.  
  3606.     case IOC_TTY_CLEAR_BREAK:        /* Not implemented. */
  3607.         goto invalid;
  3608. a765 6
  3609.     case IOC_TTY_SET_DTR:            /* Not implemented. */
  3610.         goto invalid;
  3611.  
  3612.     case IOC_TTY_CLEAR_DTR:            /* Not implemented. */
  3613.         goto invalid;
  3614.  
  3615. d767 1
  3616. a767 1
  3617.         if (reqPtr->hdr.hdr.requestSize != 0) {
  3618. d770 1
  3619. a770 1
  3620.         reply.data.owner.id = tPtr->owner;
  3621. d772 1
  3622. a772 1
  3623.         reply.data.owner.procOrFamily = IOC_OWNER_FAMILY;
  3624. d774 1
  3625. a774 1
  3626.         reply.data.owner.procOrFamily = IOC_OWNER_PROC;
  3627. d776 2
  3628. a777 1
  3629.         reply.hdr.replySize = sizeof(Ioc_Owner);
  3630. d781 1
  3631. a781 1
  3632.         if (reqPtr->hdr.hdr.requestSize != sizeof(Ioc_Owner)) {
  3633. d784 2
  3634. a785 2
  3635.         tPtr->owner = reqPtr->data.owner.id;
  3636.         if (reqPtr->data.owner.procOrFamily == IOC_OWNER_FAMILY) {
  3637. d793 3
  3638. a795 11
  3639.         /*
  3640.          * We ignore the request, but the kernel sticks in the offset
  3641.          * and makes the argument be an integer.  So, if this check
  3642.          * is actually needed, it should at least get the check right!
  3643.          */
  3644.         if (reqPtr->hdr.hdr.requestSize != sizeof(int)) {
  3645.         goto invalid;
  3646.         }
  3647.         reply.data.i = tPtr->lastBreak - tPtr->lastRemoved;
  3648.         if (reply.data.i < 0) {
  3649.         reply.data.i += tPtr->bufferSize;
  3650. d797 2
  3651. a798 1
  3652.         reply.hdr.replySize = sizeof(int);
  3653. d802 1
  3654. a802 1
  3655.         if (reqPtr->hdr.hdr.requestSize != 0) {
  3656. d805 2
  3657. a806 2
  3658.         reply.data.tchars = tPtr->tchars;
  3659.         reply.hdr.replySize = sizeof(struct tchars);
  3660. d810 1
  3661. a810 1
  3662.         if (reqPtr->hdr.hdr.requestSize != sizeof(struct tchars)) {
  3663. d813 9
  3664. a821 1
  3665.         tPtr->tchars = reqPtr->data.tchars;
  3666. d825 1
  3667. a825 1
  3668.         if (reqPtr->hdr.hdr.requestSize != sizeof(int)) {
  3669. d828 1
  3670. a828 1
  3671.         tPtr->localMode |= reqPtr->data.i;
  3672. d832 1
  3673. a832 1
  3674.         if (reqPtr->hdr.hdr.requestSize != sizeof(int)) {
  3675. d835 1
  3676. a835 1
  3677.         tPtr->localMode &= ~reqPtr->data.i;
  3678. d839 1
  3679. a839 1
  3680.         if (reqPtr->hdr.hdr.requestSize != sizeof(int)) {
  3681. d842 1
  3682. a842 1
  3683.         tPtr->localMode = reqPtr->data.i;
  3684. d846 1
  3685. a846 1
  3686.         if (reqPtr->hdr.hdr.requestSize != 0) {
  3687. d849 2
  3688. a850 2
  3689.         reply.data.i = tPtr->localMode;
  3690.         reply.hdr.replySize = sizeof(int);
  3691. d854 1
  3692. a854 1
  3693.         if (reqPtr->hdr.hdr.requestSize != sizeof(struct ltchars)) {
  3694. d857 1
  3695. a857 1
  3696.         tPtr->ltchars = reqPtr->data.ltchars;
  3697. d861 1
  3698. a861 1
  3699.         if (reqPtr->hdr.hdr.requestSize != 0) {
  3700. d864 2
  3701. a865 2
  3702.         reply.data.ltchars = tPtr->ltchars;
  3703.         reply.hdr.replySize = sizeof(struct ltchars);
  3704. d869 3
  3705. a871 2
  3706.         reply.hdr.replySize = sizeof(int);
  3707.         reply.data.i = 0;
  3708. d877 16
  3709. a892 1
  3710.         
  3711. d897 313
  3712. d1211 3
  3713. a1213 2
  3714.      * Send the reply back to the application.  We pass a reply to the
  3715.      * kernel which includes a size and an address for any reply data.
  3716. d1216 8
  3717. a1223 13
  3718.     reply.hdr.magic = PDEV_REPLY_MAGIC;
  3719.     reply.hdr.status = SUCCESS;
  3720.     if (reply.hdr.replySize != reqPtr->hdr.hdr.replySize) {
  3721.     goto invalid;
  3722.     }
  3723.     reply.hdr.selectBits = TdSelectBits(tPtr);
  3724.     reply.hdr.replyBuf = &reply.data.chars[0];
  3725.     status = Fs_IOControl(applPtr->streamID, IOC_PDEV_REPLY,
  3726.                 sizeof(Pdev_Reply), (Address) &reply,
  3727.                 0, (Address) NULL);
  3728.     if (status != SUCCESS) {
  3729.     panic("%s; status \"%s\"", "Td_Ioc couldn't send reply",
  3730.         Stat_GetMsg(status));
  3731. d1225 5
  3732. a1229 1
  3733.     return;
  3734. d1231 5
  3735. a1235 2
  3736.     invalid:
  3737.     TdReply(applPtr, (ReturnStatus) FS_INVALID_ARG, TdSelectBits(tPtr));
  3738. d1241 1
  3739. a1241 1
  3740.  * TdReply --
  3741. d1243 3
  3742. a1245 2
  3743.  *    Send a reply back with no data;  just a return status.  This
  3744.  *    procedure is most often used for error returns.
  3745. d1251 2
  3746. a1252 2
  3747.  *    The application will receive status as the return from the
  3748.  *    system call it invoked.
  3749. d1257 6
  3750. a1262 5
  3751. static void
  3752. TdReply(applPtr, status, selectBits)
  3753.     ApplStream *applPtr;    /* Application stream info. */
  3754.     ReturnStatus status;    /* Error code to send to application. */
  3755.     int selectBits;        /* Current select state for the stream */
  3756. a1263 13
  3757.     Pdev_Reply reply;
  3758.  
  3759.     reply.magic = PDEV_REPLY_MAGIC;
  3760.     reply.selectBits = selectBits;
  3761.     reply.status = status;
  3762.     reply.replySize = 0;
  3763.     reply.replyBuf = NULL;
  3764.     status = Fs_IOControl(applPtr->streamID, IOC_PDEV_REPLY,
  3765.         sizeof(Pdev_Reply), (Address) &reply, 0, (Address) NULL);
  3766.     if (status != SUCCESS) {
  3767.     panic("%s; status \"%s\"", "Td_Reply couldn't send reply",
  3768.         Stat_GetMsg(status));
  3769.     }
  3770. d1269 1
  3771. a1269 1
  3772.  * TdSelectBits --
  3773. d1271 4
  3774. a1274 4
  3775.  *    Return the current select state of the tty stream.  This
  3776.  *    examines the mode of the tty and decides if there are any
  3777.  *    characters available for reading.  The stream is always
  3778.  *    writable, but never exceptable.
  3779. a1275 3
  3780.  *    Note, this doesn't pay any attention to terminal ownership,
  3781.  *    although it could.
  3782.  *
  3783. d1277 1
  3784. a1277 2
  3785.  *    An or'd combination of FS_READABLE and FS_WRITABLE that
  3786.  *    indicate the current select state.
  3787. d1280 2
  3788. a1281 1
  3789.  *    None.
  3790. d1286 4
  3791. a1289 3
  3792. static int
  3793. TdSelectBits(tPtr)
  3794.     register Terminal *tPtr;
  3795. d1291 40
  3796. a1330 1
  3797.     register int selectBits = FS_WRITABLE;
  3798. d1332 11
  3799. a1342 2
  3800.     if (tPtr->lastBreak != tPtr->lastRemoved) {
  3801.     selectBits |= FS_READABLE;
  3802. d1344 3
  3803. a1346 1
  3804.     return(selectBits);
  3805. d1360 2
  3806. a1361 2
  3807.  *    The appropriate echo sequence for c get written to the 
  3808.  *    terminal's output stream.
  3809. d1400 1
  3810. a1400 1
  3811.  * TdPutChar --
  3812. d1402 2
  3813. a1403 4
  3814.  *    Output a character to the device associated with a terminal,
  3815.  *    and keep track of the current column while outputting the
  3816.  *    character.  This routine also substitutes spaces for tabs,
  3817.  *    if that's the mode the terminal is in.
  3818. d1409 1
  3819. a1409 2
  3820.  *    TPtr->column gets updated and stuff gets added to the device's
  3821.  *    output stream.
  3822. d1415 4
  3823. a1418 3
  3824. TdPutChar(tPtr, c)
  3825.     register Terminal *tPtr;    /* Terminal on which to output. */
  3826.     char c;            /* Character to output. */
  3827. d1420 5
  3828. a1424 18
  3829.     register FILE *stream = tPtr->outputStream;
  3830.  
  3831.     if (isprint(c)) {
  3832.     tPtr->column += 1;
  3833.     } else if (c == '\r') {
  3834.     tPtr->column = 0;
  3835.     } else if (c == '\t') {
  3836.     int count = 8 - (tPtr->column & 07);
  3837.  
  3838.     tPtr->column += count;
  3839.     if ((tPtr->sgttyb.sg_flags & TBDELAY) == XTABS) {
  3840.         for ( ; count > 0; count--) {
  3841.         putc(' ', stream);
  3842.         }
  3843.         return;
  3844.     }
  3845.     } else if (c == '\b') {
  3846.     tPtr->column -= 1;
  3847. d1426 1
  3848. a1426 1
  3849.     putc(c, stream);
  3850. d1436 2
  3851. a1437 1
  3852.  *    in tPtr's buffer.  Also remove the character from the buffer.
  3853. d1443 2
  3854. a1444 2
  3855.  *    TPtr's buffer ends up with one less character in it.  Stuff
  3856.  *    gets output on tPtr's outputStream.
  3857. d1465 1
  3858. a1465 1
  3859.         if (tPtr->lastAdded == tPtr->lastHidden) {
  3860. d1467 1
  3861. a1467 1
  3862.         if (c == -1) {
  3863. d1472 1
  3864. a1472 1
  3865.         TdRetypeInput(tPtr, tPtr->lastRemoved);
  3866. d1475 1
  3867. a1475 1
  3868.         c = tPtr->inputBuffer[tPtr->lastAdded];
  3869. d1492 2
  3870. a1493 2
  3871.             NEXT(i, tPtr->bufferSize, i);
  3872.             if (i == tPtr->lastAdded) {
  3873. d1524 1
  3874. a1524 1
  3875.          * between "\" and "/" delimeters.
  3876. d1531 1
  3877. a1531 1
  3878.         TdEcho(tPtr, tPtr->inputBuffer[tPtr->lastAdded]);
  3879. d1537 1
  3880. a1537 1
  3881.     
  3882. d1541 1
  3883. a1541 1
  3884.     PREV(tPtr->lastAdded, tPtr->bufferSize, tPtr->lastAdded);
  3885. d1547 1
  3886. a1547 1
  3887.  * TdSignal --
  3888. d1549 1
  3889. a1549 2
  3890.  *    Generate a signal for the process group associated with a
  3891.  *    terminal.
  3892. d1555 1
  3893. a1555 2
  3894.  *    Processes get signalled (unless there's no process group for
  3895.  *    the terminal).  The terminal's buffer gets flushed.
  3896. d1561 2
  3897. a1562 3
  3898. TdSignal(tPtr, signal)
  3899.     register Terminal *tPtr;        /* Terminal for which to signal. */
  3900.     int signal;                /* Number of signal to generate. */
  3901. d1564 3
  3902. a1566 30
  3903.     TdFlushInput(tPtr);
  3904.     if (tPtr->owner != 0) {
  3905.     Sig_Send(signal, tPtr->owner, tPtr->flags & OWNER_FAMILY);
  3906.     }
  3907. }
  3908.  
  3909. /*
  3910.  *----------------------------------------------------------------------
  3911.  *
  3912.  * TdRetypeInput --
  3913.  *
  3914.  *    This procedure is called to re-echo all of the characters in
  3915.  *    the input buffer.
  3916.  *
  3917.  * Results:
  3918.  *    None.
  3919.  *
  3920.  * Side effects:
  3921.  *    Characters get written to the terminal device.
  3922.  *
  3923.  *----------------------------------------------------------------------
  3924.  */
  3925.  
  3926. void
  3927. TdRetypeInput(tPtr, start)
  3928.     register Terminal *tPtr;    /* Which terminal to re-echo for. */
  3929.     int start;            /* Index within tPtr's buffer:  start
  3930.                  * echoing at the character AFTER this one. */
  3931. {
  3932.     tPtr->keyIndex = tPtr->lastRemoved;
  3933. d1568 1
  3934. a1568 5
  3935.     while (start != tPtr->lastAdded) {
  3936.     NEXT(start, tPtr->bufferSize, start);
  3937.     TdEcho(tPtr, tPtr->inputBuffer[start]);
  3938.     }
  3939.     tPtr->lastHidden = -1;
  3940. d1574 1
  3941. a1574 1
  3942.  * TdFlushInput --
  3943. d1576 1
  3944. a1576 1
  3945.  *    Empty the input buffer associated with a terminal.
  3946. d1582 4
  3947. a1585 1
  3948.  *    TPtr's input buffer is flushed.
  3949. d1591 1
  3950. a1591 1
  3951. TdFlushInput(tPtr)
  3952. d1594 6
  3953. a1599 5
  3954.     tPtr->lastAdded = tPtr->lastRemoved = 0;
  3955.     tPtr->lastBreak = tPtr->keyIndex = 0;
  3956.     tPtr->lastHidden = -1;
  3957.     tPtr->keyColumn = tPtr->column;
  3958.     tPtr->flags &= ~(LITERAL_NEXT|BS_IN_PROGRESS);
  3959. @
  3960.  
  3961.  
  3962. 1.8
  3963. log
  3964. @Make PDEV_WRITE_ASYNC equivalent to PDEV_WRITE.
  3965. @
  3966. text
  3967. @d19 1
  3968. a19 1
  3969. static char rcsid[] = "$Header: /sprite/src/lib/c/etc/RCS/ttyDriver.c,v 1.7 89/01/16 10:39:54 ouster Exp Locker: ouster $ SPRITE (Berkeley)";
  3970. d33 1
  3971. d241 17
  3972. a257 17
  3973. extern void    TdApplRequest();
  3974. extern void    TdBackspace();
  3975. extern void    TdClose();
  3976. extern void    TdControlRequest();
  3977. extern void    TdEcho();
  3978. extern void    TdFlushInput();
  3979. extern void    TdFlushPdev();
  3980. extern void    TdIoc();
  3981. extern void    TdOpen();
  3982. extern void    TdPutChar();
  3983. extern void    TdRead();
  3984. extern int    TdReady();
  3985. extern void    TdReply();
  3986. extern void    TdRetypeInput();
  3987. extern void    TdSignal();
  3988. extern void    TdWrite();
  3989. extern int    TdSelectBits();
  3990. d671 3
  3991. a673 3
  3992.     Tty_BasicParams *basicPtr;        /* Where to store sgttyb stuff. */
  3993.     Tty_Chars *charsPtr;        /* Where to store tchars stuff. */
  3994.     Tty_LocalChars *localCharsPtr;    /* Where to store ltchars stuff. */
  3995. d703 3
  3996. a705 3
  3997.     Tty_BasicParams *basicPtr;        /* New sgttyb stuff. */
  3998.     Tty_Chars *charsPtr;        /* New tchars. */
  3999.     Tty_LocalChars *localCharsPtr;    /* New ltchars. */
  4000. @
  4001.  
  4002.  
  4003. 1.7
  4004. log
  4005. @Changed handling of hidden characters to make it more like UNIX.
  4006. @
  4007. text
  4008. @d19 1
  4009. a19 1
  4010. static char rcsid[] = "$Header: ttyDriver.c,v 1.6 88/10/14 13:09:19 brent Exp $ SPRITE (Berkeley)";
  4011. d853 1
  4012. @
  4013.  
  4014.  
  4015. 1.6
  4016. log
  4017. @Updated to new Pdev_Request declaration
  4018. @
  4019. text
  4020. @d19 1
  4021. a19 1
  4022. static char rcsid[] = "$Header: ttyDriver.c,v 1.5 88/10/07 19:00:59 douglis Exp $ SPRITE (Berkeley)";
  4023. d111 3
  4024. a113 3
  4025.                  * them.  -1 means none of the characters in
  4026.                  * the buffer arrived before the last output
  4027.                  * to the terminal. */
  4028. d532 1
  4029. a532 1
  4030.         if (!(tPtr->localMode & LCRTKIL)) {
  4031. d536 1
  4032. d634 1
  4033. d1602 6
  4034. d1609 1
  4035. @
  4036.  
  4037.  
  4038. 1.5
  4039. log
  4040. @fixed bad check for size of arg to ioctl.
  4041. @
  4042. text
  4043. @d19 1
  4044. a19 1
  4045. static char rcsid[] = "$Header: ttyDriver.c,v 1.4 88/09/28 10:06:32 brent Exp $ SPRITE (Berkeley)";
  4046. a27 1
  4047. #include <fs.h>
  4048. d835 1
  4049. a835 1
  4050.     if (requestPtr->hdr.magic != PDEV_REQUEST_MAGIC) {
  4051. d837 1
  4052. a837 1
  4053.                 requestPtr->hdr.magic);
  4054. d840 1
  4055. a840 1
  4056.     switch (requestPtr->hdr.operation) {
  4057. d858 1
  4058. a858 1
  4059.             requestPtr->hdr.operation);
  4060. d863 1
  4061. a863 1
  4062.     bufPtrs.requestFirstByte += requestPtr->hdr.messageSize;
  4063. d896 1
  4064. a896 1
  4065.     if (reqPtr->hdr.requestSize != 0) {
  4066. d898 1
  4067. a898 1
  4068.         reqPtr->hdr.requestSize);
  4069. d985 1
  4070. a985 1
  4071.     if (reqPtr->hdr.requestSize != 0) {
  4072. d987 1
  4073. a987 1
  4074.         reqPtr->hdr.requestSize);
  4075. d1046 1
  4076. a1046 1
  4077.     if (reply.hdr.replySize >= reqPtr->hdr.replySize) {
  4078. d1118 2
  4079. a1119 2
  4080.     for (p = reqPtr->data.chars; reqPtr->hdr.requestSize > 0;
  4081.      p++, reqPtr->hdr.requestSize--) {
  4082. d1180 1
  4083. a1180 1
  4084.         if ((reqPtr->hdr.requestSize != sizeof(int))
  4085. d1187 1
  4086. a1187 1
  4087.         if (reqPtr->hdr.requestSize != 0) {
  4088. d1195 1
  4089. a1195 1
  4090.         if (reqPtr->hdr.requestSize != 0) {
  4091. d1205 1
  4092. a1205 1
  4093.         if (reqPtr->hdr.requestSize != sizeof(struct sgttyb)) {
  4094. d1215 1
  4095. a1215 1
  4096.         if (reqPtr->hdr.requestSize != 0) {
  4097. d1222 1
  4098. a1222 1
  4099.         if (reqPtr->hdr.requestSize != 0) {
  4100. d1232 1
  4101. a1232 1
  4102.         if (reqPtr->hdr.requestSize != 0) {
  4103. d1239 1
  4104. a1239 1
  4105.         if (reqPtr->hdr.requestSize != 1) {
  4106. d1258 1
  4107. a1258 1
  4108.         if (reqPtr->hdr.requestSize != 0) {
  4109. d1271 1
  4110. a1271 1
  4111.         if (reqPtr->hdr.requestSize != sizeof(Ioc_Owner)) {
  4112. d1288 1
  4113. a1288 1
  4114.         if (reqPtr->hdr.requestSize != sizeof(int)) {
  4115. d1299 1
  4116. a1299 1
  4117.         if (reqPtr->hdr.requestSize != 0) {
  4118. d1307 1
  4119. a1307 1
  4120.         if (reqPtr->hdr.requestSize != sizeof(struct tchars)) {
  4121. d1314 1
  4122. a1314 1
  4123.         if (reqPtr->hdr.requestSize != sizeof(int)) {
  4124. d1321 1
  4125. a1321 1
  4126.         if (reqPtr->hdr.requestSize != sizeof(int)) {
  4127. d1328 1
  4128. a1328 1
  4129.         if (reqPtr->hdr.requestSize != sizeof(int)) {
  4130. d1335 1
  4131. a1335 1
  4132.         if (reqPtr->hdr.requestSize != 0) {
  4133. d1343 1
  4134. a1343 1
  4135.         if (reqPtr->hdr.requestSize != sizeof(struct ltchars)) {
  4136. d1350 1
  4137. a1350 1
  4138.         if (reqPtr->hdr.requestSize != 0) {
  4139. d1377 1
  4140. a1377 1
  4141.     if (reply.hdr.replySize != reqPtr->hdr.replySize) {
  4142. @
  4143.  
  4144.  
  4145. 1.4
  4146. log
  4147. @Updated to latest typedefs
  4148. @
  4149. text
  4150. @d19 1
  4151. a19 1
  4152. static char rcsid[] = "$Header: ttyDriver.c,v 1.3 88/07/28 17:47:40 ouster Exp $ SPRITE (Berkeley)";
  4153. d1284 6
  4154. a1289 1
  4155.         if (reqPtr->hdr.requestSize != 0) {
  4156. @
  4157.  
  4158.  
  4159. 1.3
  4160. log
  4161. @Lint.
  4162. @
  4163. text
  4164. @d19 1
  4165. a19 1
  4166. static char rcsid[] = "$Header: ttyDriver.c,v 1.2 88/07/25 13:27:45 ouster Exp $ SPRITE (Berkeley)";
  4167. d203 1
  4168. a203 1
  4169.     Pdev_NewRequest hdr;
  4170. d226 1
  4171. a226 1
  4172.     Pdev_NewReply hdr;
  4173. d1056 1
  4174. a1056 1
  4175.     replyPtr = (Reply *) malloc((unsigned) (sizeof(Pdev_NewReply)
  4176. d1076 1
  4177. a1076 1
  4178.                 sizeof(Pdev_NewReply),
  4179. d1379 1
  4180. a1379 1
  4181.                 sizeof(Pdev_NewReply), (Address) &reply,
  4182. d1415 1
  4183. a1415 1
  4184.     Pdev_NewReply reply;
  4185. d1423 1
  4186. a1423 1
  4187.         sizeof(Pdev_NewReply), (Address) &reply, 0, (Address) NULL);
  4188. @
  4189.  
  4190.  
  4191. 1.2
  4192. log
  4193. @Lint.
  4194. @
  4195. text
  4196. @d19 1
  4197. a19 1
  4198. static char rcsid[] = "$Header: ttyDriver.c,v 1.1 88/07/01 09:40:52 ouster Exp $ SPRITE (Berkeley)";
  4199. d778 1
  4200. a778 1
  4201.             sizeof(int), (Address)&true, 0, NULL);
  4202. d780 2
  4203. a781 1
  4204.             sizeof(Pdev_SetBufArgs), (Address)&setBuf, 0, NULL);
  4205. d783 1
  4206. a783 1
  4207.         (Address) applPtr);
  4208. d867 1
  4209. a867 1
  4210.             0, NULL);
  4211. d1077 1
  4212. a1077 1
  4213.                 (Address) replyPtr, 0, NULL);
  4214. d1102 1
  4215. d1379 2
  4216. a1380 1
  4217.                 sizeof(Pdev_NewReply), (Address) &reply, 0, NULL);
  4218. d1423 1
  4219. a1423 1
  4220.         sizeof(Pdev_NewReply), (Address) &reply, 0, NULL);
  4221. @
  4222.  
  4223.  
  4224. 1.1
  4225. log
  4226. @Initial revision
  4227. @
  4228. text
  4229. @d19 1
  4230. a19 1
  4231. static char rcsid[] = "$Header: ttyDriver.c,v 2.9 88/05/24 17:13:38 deboor Exp $ SPRITE (Berkeley)";
  4232. a311 1
  4233.     ReturnStatus status;
  4234. a811 1
  4235.     ReturnStatus status;
  4236. @
  4237.